当前位置: 移动技术网 > IT编程>移动开发>IOS > ios学习路线—Objective-C(深浅拷贝)

ios学习路线—Objective-C(深浅拷贝)

2018年12月18日  | 移动技术网IT编程  | 我要评论

新浪爱彩,管沛林,程小烦

在objc中,什么是深浅拷贝?  深浅拷贝分别指深拷贝和浅拷贝,即 mutablecopy 和 copy 方法。  copy复制一个不可变对象,而 mutablecopy 复制一个 mutable 可变对象。

 

非容器类对象  如nsstring,nsnumber等一类对象 
示例1:

// 非容器类对象
    nsstring *str = @"origin string";
    nsstring *strcopy = [str copy];
    nsmutablestring *mstrcopy = [str mutablecopy];
    [mstrcopy appendstring:@"??"];

//    nslog(@"array1     = %p", array1);
//    nslog(@"arraycopy1 = %p", arraycopy1);

查看内存可以发现,str和strcopy指向的是同一块内存区域,我们称之为弱引用(weak reference)。而mstrcopy是真正的复制,系统为其分配了新内存空间,保存从str复制过来的字符串值。从最后一行代码中修改这些值而不影 响str和strcopy中可证明。

示例2:

    nsmutablestring *mstr = [nsmutablestring stringwithstring:@"origin"];
    nsstring *strcopy = [mstr copy];
    nsmutablestring *mstrcopy = [mstr copy];
    nsmutablestring *mstrmcopy = [mstr mutablecopy];
    //[mstrcopy appendstring:@"1111"];  //error
    [mstr appendstring:@"222"];
    [mstrmcopy appendstring:@"333"];

以上四个对象所分配的内存都是不一样的。而且对于mstrcopy,它所指向的其实是一个imutable对象,是不可改变的,所以会出错。这点要注意,好好理解。

小结: 
1.如果对一个不可变对象复制,copy是指针复制,即浅拷贝;而mutablecopy则是对象复制,即深拷贝。 
2.如果是对可变对象复制,都是深拷贝,但是copy复制返回的对象是不可变的。

容器类对象深浅复制 
比如nsarray,nsdictionary等。对于容器类本身,上面讨论的结论也适用的,下面探讨的是复制后容器内对象的变化。

示例3:

    /* copy返回不可变对象,mutablecopy返回可变对象 */
    nsarray *array1     = [nsarray arraywithobjects:@"a",@"b",@"c",nil];
    nsarray *arraycopy1 = [array1 copy];
    //arraycopy1是和array同一个nsarray对象(指向相同的对象),包括array里面的元素也是指向相同的指针
    nslog(@"array1 retain count: %d",[array1 retaincount]);      // 2
    nslog(@"array1 retain count: %d",[arraycopy1 retaincount]);    //  2

    nsmutablearray *marraycopy1 = [array1 mutablecopy];
    //marraycopy1是array1的可变副本,指向的对象和array1不同,但是其中的元素和array1中的元素指向的还是同一个对象。marraycopy1还可以修改自己的对象
    [marraycopy1 addobject:@"de"];
    [marraycopy1 removeobjectatindex:0];

array1和arraycopy1是指针复制,而marraycopy1是对象复制,符合前面示例1讨论的结论。marraycopy1可以改变其内的元素:删除或添加。但容器内的元素内容都是浅拷贝。

 

示例4

    nsarray *marray1 = [nsarray arraywithobjects:[nsmutablestring stringwithstring:@"a"],@"b",@"c",nil];
    nslog(@"marray1 retain count: %d",[marray1 retaincount]);
    nsarray *marraycopy2 = [marray1 copy];
    nslog(@"marray1 retain count: %d",[marray1 retaincount]);
    // marray1和marraycopy2指向同一对象,retain值+1。

    nsmutablearray *marraymcopy1 = [marray1 mutablecopy];
    nslog(@"marray1 retain count: %d",[marray1 retaincount]);
    //marraycopy2和marray1指向的是不一样的对象,但是其中的元素都是一样的对象——同一个指针

    nsmutablestring *teststring = [marray1 objectatindex:0];
    //teststring = @"1a1";//这样会改变teststring的指针,其实是将@“1a1”临时对象赋给了teststring
    [teststring appendstring:@" tail"];//这样以上三个数组的首元素都被改变了

由此可见,对于容器而言,其元素对象始终是指针复制。如果需要元素对象也是对象复制,就需要实现深拷贝。

 

示例5

nsarray *array = [nsarray arraywithobjects:[nsmutablestring stringwithstring:@"first"] ,[nsstring stringwithstring:@"b"],@"c",nil];
nsarray *deepcopyarray=[[nsarray alloc] initwitharray: array copyitems: yes];
nslog(@"array[2] = %@, deepcopyarray[2]=%@ ",[array objectatindex:2], [deepcopyarray objectatindex:2]);  //输出值是一样的
nslog(@"array[2]         %p", [array objectatindex:2]);
nslog(@"deepcopyarray[2] %p", [deepcopyarray objectatindex:2]);   
  //最后两个打印的log内存地址值是一样的


nsarray* truedeepcopyarray = [nskeyedunarchiver unarchiveobjectwithdata:[nskeyedarchiver archiveddatawithrootobject: array]];

truedeepcopyarray 是完全意义上的深拷贝,而deepcopyarray则不是,对于 deepcopyarray 内的不可变元素其还是指针复制。

 

自己实现深拷贝的方法 nsdictionarymutabledeepcopy.h

#import <foundation /foundation.h>
@interface nsdictionary(mutabledeepcopy)
- (nsmutabledictionary *)mutabledeepcopy;
@end

nsdictionarymutabledeepcopy.m

#import "nsdictionarymutabledeepcopy.h"
@implementation nsdictionary(mutabledeepcopy)
- (nsmutabledictionary *)mutabledeepcopy {
    nsmutabledictionary *ret = [[nsmutabledictionary alloc]
                                initwithcapacity:[self count]];
    nsarray *keys = [self allkeys];
    for (id key in keys) {
        id onevalue = [self valueforkey:key];
        id onecopy = nil;
        if ([onevalue respondstoselector:@selector(mutabledeepcopy)]) {
            onecopy = [onevalue mutabledeepcopy];
        }
        else if ([onevalue respondstoselector:@selector(mutablecopy)]) {
            onecopy = [onevalue mutablecopy];
        }
        if (onecopy == nil) {
            onecopy = [onevalue copy];
        }
        [ret setvalue:onecopy forkey:key];
    }
    return ret;
}

使用类别方法来实现 
如果是我们定义的对象,那么我们自己要实现nscopying,nsmutablecopying这样就能调用copy和mutablecopy了。举个例子

@interface myobj : nsobject<nscopying ,nsmutablecopying>
{
         nsmutablestring *name;
         nsstring *imutablestr;
         int age;
}
@property (nonatomic, retain) nsmutablestring *name;
@property (nonatomic, retain) nsstring *imutablestr;
@property (nonatomic) int age;

@end

@implementation myobj
@synthesize name;
@synthesize age;
@synthesize imutablestr;
- (id)init
{
         if (self = [super init])
         {
                   self.name = [[nsmutablestring alloc]init];
                   self.imutablestr = [[nsstring alloc]init];
                   age = -1;
         }
         return self;
}

- (void)dealloc
{
         [name release];
         [imutablestr release];
         [super dealloc];
}
- (id)copywithzone:(nszone *)zone
{
         myobj *copy = [[[self class] allocwithzone:zone] init];
         copy->name = [name copy];
         copy->imutablestr = [imutablestr copy];
//       copy->name = [name copywithzone:zone];;
//       copy->imutablestr = [name copywithzone:zone];//
         copy->age = age;
         return copy;
}
- (id)mutablecopywithzone:(nszone *)zone
{
    myobj *copy = nscopyobject(self, 0, zone);
    copy->name = [self.name mutablecopy];
    copy->age = age;
    return copy;
}
@end

如对本文有疑问,请在下面进行留言讨论,广大热心网友会与你互动!! 点击进行留言回复

相关文章:

验证码:
移动技术网