IOS 关于对象的复制问题

来源:互联网 发布:节假日堵车数据 编辑:程序博客网 时间:2024/06/04 21:53


最近在学习IOS的程序,根据IOS5基础教程编码,在第8章的Search时,提到一个深度复制的概念,后来重新学习了下Objective-C中的copy,mutablecopy,以及其他一些方法,先将相关学习经验记录下来。

XCODE 版本是4.6.3 模拟器是IPHONE6.1,在测试时发现与很多书上,以及网上的资料不符合,不知道是不是苹果新的编译器改动的问题。

1.针对非容器类型

如 NSString,NSMutableString 
   
如果对一不可变对象复制,copy是指针复制(浅拷贝)和mutableCopy就是对象复制
使用mutableCopy复制完后,对象是相互独立;
如下:
    
  NSString *string1=[[NSStringalloc] initWithFormat:@"1111"];    NSString *string2=[string1 copy];    //string2 是string1 的指针复制     NSMutableString *mstring3=[[NSMutableStringalloc] init];    [mstring3 appendString:string1];     // 关于 appendString的使用在后面章节将会介绍,其实这时一个对象复制(深拷贝)    NSMutableString *mstring4=[mstring3 mutableCopy];    //使用mutableCopy后 mstring4拥有了和mstring3一样的内容,但是他们所指向的对象时完全不同的    NSLog(@"string1 %@",string1);    NSLog(@"string2 %@",string2);    NSLog(@"string3 %@",mstring3);    NSLog(@"string4 %@",mstring4);        [mstring3 appendString:@"22222"];     //通过修改mstring3 ,可以发现因为其使用了 appendString,所以他与string1已经是2个不同的对象了     //因为mstring4使用的是mutableCopy,这也是一个深拷贝,所以mstring4也没有收到影响    NSLog(@"string1 %@",string1);    NSLog(@"string2 %@",string2);    NSLog(@"string3 %@",mstring3);    NSLog(@"string4 %@",mstring4);        /*     输出如下:     2013-07-27 20:53:11.818 sections[6371:c07] string1 1111     2013-07-27 20:53:11.819 sections[6371:c07] string2 1111     2013-07-27 20:53:11.819 sections[6371:c07] string3 1111     2013-07-27 20:53:11.819 sections[6371:c07] string4 1111     2013-07-27 20:53:11.819 sections[6371:c07] string1 1111     2013-07-27 20:53:11.820 sections[6371:c07] string2 1111     2013-07-27 20:53:11.820 sections[6371:c07] string3 111122222     2013-07-27 20:53:11.820 sections[6371:c07] string4 1111     */

2. 针对容器下的对象
NSDictionary,NSMutableDictionary,NSArray,NSMutableArray 
 NSArray *aKeys=[[NSArrayalloc] initWithObjects:@"key1",@"key2",nil];    NSArray *aValue=[[NSArrayalloc] initWithObjects:@"value1",@"value2",nil];    NSDictionary *tDic=[[NSDictionaryalloc] initWithObjects:aValue forKeys:aKeys];    NSMutableDictionary *mDic1=[tDic mutableCopy];    //一样采用mutablcopy    NSLog(@"tDic %@",tDic);    NSLog(@"mDic %@",mDic1);    [mDic1 setObject:@"mdic1"forKey:@"key1"];     //修改其中一个对象    NSLog(@"tDic %@",tDic);    NSLog(@"mDic %@",mDic1);/*2013-07-27 21:09:27.618 sections[6516:c07] tDic {    key1 = value1;    key2 = value2;}2013-07-27 21:09:27.619 sections[6516:c07] mDic {    key1 = value1;    key2 = value2;}2013-07-27 21:09:27.619 sections[6516:c07] tDic {    key1 = value1;    key2 = value2;}2013-07-27 21:09:27.619 sections[6516:c07] mDic {    key1 = mdic1;    key2 = value2;}*/
   mdic的对象已经被改变了,但是tDic的对象仍然和原来一样,说明他们指向的对象是不同的。

3.关于初始化,addObject等对象的复制
    
 NSMutableArray *array1 =  [[NSMutableArray alloc] initWithObjects:@"1",@"2",@"3",nil];        NSMutableArray *array2 = [[NSMutableArray alloc] initWithArray:array1];    NSMutableArray  *array3 =[[NSMutableArray alloc] init];    [array3 addObjectsFromArray:array1];        NSLog(@"array1 %@",array1);    NSLog(@"array2 %@",array2);    NSLog(@"array3 %@",array3);        [array2 replaceObjectAtIndex:0 withObject:@"100"];    [array3 replaceObjectAtIndex:0 withObject:@"300"];            NSLog(@"array1 %@",array1);    NSLog(@"array2 %@",array2);    NSLog(@"array3 %@",array3);        /*     2013-07-27 20:30:07.681 sections[6203:c07] array1 (     1,     2,     3     )     2013-07-27 20:30:07.681 sections[6203:c07] array2 (     100,     2,     3     )     2013-07-27 20:30:07.681 sections[6203:c07] array3 (     300,     2,     3     )     */

    结论:使用 mutablecopy,initwithArray addObjectFromArray 都是深层复制,包含非容器,容器在内的对象(容器内的对象)都是被复制的,而不是单纯的指针复制。
4.另外一些对象复制
  如果是使用容器进行初始化
    NSMutableArray *value1=[[NSMutableArray alloc]initWithObjects:@"V1",@"V2",nil];    NSMutableArray *value2=[[NSMutableArray alloc]initWithObjects:@"VV1",@"VV2",nil];        NSMutableArray *mmkey=[[NSMutableArray alloc]initWithObjects:@"key1",@"key2",nil];    NSMutableArray *mmvalue=[[NSMutableArray alloc]initWithObjects:value1,value2,nil];        NSMutableDictionary *md=[[NSMutableDictionary alloc]initWithObjects:mmvalue forKeys:mmkey];    NSMutableArray *ma=[md valueForKey:@"key1"];     NSLog(@"ma %@",ma);    NSLog(@"md %@",md);    [ma addObject:@"123"];    [value2 addObject:@"VV3"];        NSLog(@"md %@",md);    NSLog(@"ma %@",ma);    2013-07-27 23:30:45.587 sections[7778:c07] ma (    V1,    V2)2013-07-27 23:30:45.588 sections[7778:c07] md {    key1 =     (        V1,        V2    );    key2 =     (        VV1,        VV2    );}2013-07-27 23:30:45.588 sections[7778:c07] md {    key1 =     (        V1,        V2,        123    );    key2 =     (        VV1,        VV2,        VV3    );}2013-07-27 23:30:45.589 sections[7778:c07] ma (    V1,    V2,    123)

   可以看出 
   1. 字典在初始化时使用了数组对象,而这个时候是指向这些数组,而不是进行深度拷贝,后面修改了这些数组后,可以看到字典内容也发生了变化。
   2. 字典实例调用方法 valueforkey时,实际上依然是一个浅拷贝,修改这个方法返回的对象实例,也会改变字典本身。

另外这里进行一个比较有意思的实验,我们知道NSArray是一个不可变数组,但是如果他是由一个可变的NSMutableString初始化的,那么对于string的修改,是否或影响到Array呢?

    NSMutableString *S1=[[NSMutableString alloc]initWithFormat:@"123"];    NSArray *arrayy=[[NSArray alloc]initWithObjects:S1,nil];    NSLog(@"S1 %@",S1);    NSLog(@"arrayy %@",arrayy);    [S1 appendString:@"321"];        NSLog(@"S1 %@",S1);    NSLog(@"arrayy %@",arrayy);2013-07-27 23:38:53.554 sections[7850:c07] S1 1232013-07-27 23:38:53.555 sections[7850:c07] arrayy (    123)2013-07-27 23:38:53.555 sections[7850:c07] S1 1233212013-07-27 23:38:53.556 sections[7850:c07] arrayy (    123321)

我想大家一定想到了,肯定会改变。  用C++的思想 可以理解容器类的结构内部都是指针,所谓不可变指的是 const 指针,而指针指向的那个内存的内容是否可变,是根据指针对象的属性决定的。


另外在原书代码中
    NSMutableArray *keyArray = [[NSMutableArray alloc] init];    [keyArray addObject:UITableViewIndexSearch];    [keyArray addObjectsFromArray:[[self.allNames allKeys]                                   sortedArrayUsingSelector:@selector(compare:)]];    self.keys = keyArray;

已经很明显的说明 通过addObjectsFromArray的方式获取的数值是一个深度复制的数组,其实可以用同样的方法搞定NSMutableDirectionary,而不需要使用来类别,重新定义一个深度复制的方法。
另外一个需要说明的是,keys是类的一个属性,通过@property定义, 会自动生成其Setkeys的方法,可以使用.的方式进行赋值,但是这种方法调用的是copy,所以 keys和keyarray是指向同一个对象的。


    NSMutableArray *tArray=[[NSMutableArray alloc]initWithObjects:@"1",@"2", nil];    self.mKeys=tArray;   //使用.的方式赋值,其实是使用copy    NSLog(@"tArray %@",tArray);    NSLog(@"mKeys %@",self.mKeys);    [self.mKeys replaceObjectAtIndex:0 withObject:@"3"];    NSLog(@"tArray %@",tArray); // 这个时候发现tArray的值也被改变了    NSLog(@"mKeys %@",self.mKeys);         self.mKeys=[tArray mutableCopy]; //重新使用mutableCopy    [self.mKeys replaceObjectAtIndex:0 withObject:@"4"];    NSLog(@"tArray %@",tArray); //tArray的值没有被再次改变,说明他们已经指向了不同对象    NSLog(@"mKeys %@",self.mKeys);    2013-07-27 21:37:44.055 sections[6644:c07] tArray (                                                       1,                                                       2                                                       )    2013-07-27 21:37:44.056 sections[6644:c07] mKeys (                                                      1,                                                      2                                                      )    2013-07-27 21:37:44.056 sections[6644:c07] tArray (                                                       3,                                                       2                                                       )    2013-07-27 21:37:44.056 sections[6644:c07] mKeys (                                                      3,                                                      2                                                      )    2013-07-27 21:37:44.056 sections[6644:c07] tArray (                                                       3,                                                       2                                                       )    2013-07-27 21:37:44.057 sections[6644:c07] mKeys (                                                      4,                                                      2                                                      )



原创粉丝点击