专栏名称: 程序员大咖
为程序员提供最优质的博文、最精彩的讨论、最实用的开发资源;提供最新最全的编程学习资料:PHP、Objective-C、Java、Swift、C/C++函数库、.NET Framework类库、J2SE API等等。并不定期奉送各种福利。
目录
相关文章推荐
程序猿  ·  TCP 才不傻! ·  4 天前  
码农翻身  ·  Bill Gates 和 Linus ... ·  3 天前  
OSC开源社区  ·  2024年AI编程工具的进化 ·  3 天前  
OSC开源社区  ·  如何公正评价百度开源的贡献? ·  4 天前  
51好读  ›  专栏  ›  程序员大咖

iOS 复制知识点总结

程序员大咖  · 公众号  · 程序员  · 2017-10-04 10:24

正文

点击上方“ 程序员大咖 ”,选择“置顶公众号”

关键时刻,第一时间送达!


1、系统对象的复制


不管是集合类对象,还是非集合类对象,接收到copy和mutableCopy消息时,都遵循以下准则:


  • copy返回immutable对象;所以,如果对copy返回值使用mutable对象接口就会crash;

  • mutableCopy返回mutable对象;


下图详细阐述了NSString、NSMutableString、NSArray、NSMutableArray、NSDictionary、NSMutableDictionary分别调用copy与mutableCopy方法后的结果:



1.1 非集合类对象的copy与mutableCopy


系统非集合类对象指的是NSString,NSNumber之类的对象。下面看一下非集合类NSString对象拷贝的例子:


copy


NSString * string = @ "origin" ;

NSString * stringCopy = [ string copy ];

NSMutableString * stringMCopy = [ string mutableCopy ];

NSLog (@ "%p" , string );

NSLog (@ "%p" , stringCopy );

NSLog (@ "%p" , stringMCopy );


2016 - 03 - 10 17 : 32 : 04.479 Homework [ 21715 : 2353641 ] 0x1000d0ea0

2016 - 03 - 10 17 : 32 : 04.481 Homework [ 21715 : 2353641 ] 0x1000d0ea0

2016 - 03 - 10 17 : 32 : 04.481 Homework [ 21715 : 2353641 ] 0x17006fe40


通过查看内存,可以看到stringCopy和string的地址是一样,进行了指针拷贝;而stringMCopy的地址和string不一样,进行了内容拷贝。


mutableCopy


NSMutableString * string = [ NSMutableString stringWithString : @ "origin" ];

//copy

NSString * stringCopy = [ string copy ];

NSMutableString * mStringCopy = [ string copy ];

NSMutableString * stringMCopy = [ string mutableCopy ];

NSLog (@ "%p" , string );

NSLog (@ "%p" , stringCopy );

NSLog (@ "%p" , mStringCopy );

NSLog (@ "%p" , stringMCopy );


2016 - 03 - 10 17 : 34 : 11.486 Homework [ 21728 : 2354359 ] 0x17426f800

2016 - 03 - 10 17 : 34 : 11.487 Homework [ 21728 : 2354359 ] 0x174230600

2016 - 03 - 10 17 : 34 : 11.487 Homework [ 21728 : 2354359 ] 0x1742306e0

2016 - 03 - 10 17 : 34 : 11.487 Homework [ 21728 : 2354359 ] 0x174267240


//change value

[ mStringCopy appendString : @ "mm" ]; //crash

[ string appendString : @ " origion!" ];

[ stringMCopy appendString : @ "!!" ];


crash的原因就是copy返回的对象是immutable对象。


1.2 集合类对象的copy与mutableCopy


集合类对象是指NSArray、NSDictionary、NSSet之类的对象。下面看一下集合类NSArray对象使用copy和mutableCopy的一个例子:


copy


NSArray * array = @[@[@ "a" , @ "b" ], @[@ "c" , @ "d" ]];

NSArray * copyArray = [ array copy ];

NSMutableArray * mCopyArray = [ array mutableCopy ];

NSLog (@ "%p" , array );

NSLog (@ "%p" , copyArray );

NSLog (@ "%p" , mCopyArray );


2016 - 03 - 10 17 : 53 : 40.113 Homework [ 21775 : 2358227 ] 0x17403f040

2016 - 03 - 10 17 : 53 : 40.114 Homework [ 21775 : 2358227 ] 0x17403f040

2016 - 03 - 10 17 : 53 : 40.114 Homework [ 21775 : 2358227 ] 0x174247e60


可以看到copyArray和array的地址是一样的,而mCopyArray和array的地址是不同的。说明copy操作进行了指针拷贝,mutableCopy进行了内容拷贝。但需要强调的是:此处的内容拷贝,仅仅是拷贝array这个对象,array集合内部的元素仍然是指针拷贝。这和上面的非集合immutable对象的拷贝还是挺相似的,那么mutable对象的拷贝会不会类似呢?我们继续往下,


mutableCopy


NSMutableArray * array = [ NSMutableArray arrayWithObjects : [ NSMutableString stringWithString : @ "a" ],@ "b" ,@ "c" , nil ];

NSArray * copyArray = [ array copy ];

NSMutableArray * mCopyArray = [ array mutableCopy ];

NSLog (@ "%p" , array );

NSLog (@ "%p" , copyArray );

NSLog (@ "%p" , mCopyArray );


2016 - 03 - 10 17 : 54 : 39.114 Homework [ 21782 : 2358605 ] 0x170058e40

2016 - 03 - 10 17 : 54 : 39.115 Homework [ 21782 : 2358605 ] 0x170058ed0

2016 - 03 - 10 17 : 54 : 39.115 Homework [ 21782 : 2358605 ] 0x170058ea0


查看内存,如我们所料,copyArray、mCopyArray和array的内存地址都不一样,说明copyArray、mCopyArray都对array进行了内容拷贝。


2、自定义对象的复制


使用copy和mutableCopy复制对象的副本使用起来确实方便,那么我们自定义的类是否可调用copy与mutableCopy方法来复制副本呢?我们先定义一个Person类,代码如下:


@ interface Person : NSObject

@ property ( nonatomic , assign ) NSInteger age ;

@ property ( nonatomic , copy ) NSString * name ;

@ end


然后尝试调用Person的copy方法来复制一个副本:


Person * person1 = [[ Person alloc ] init ]; //创建一个Person对象

person1 . age = 20 ;

person1 . name = @ "张三" ;

Person * person2 = [ person1 copy ]; //复制副本


运行程序,将会发生崩溃,并输出以下错误信息:


[ Person copyWithZone : ] : unrecognized selector sent to instance 0x608000030920


上面的提示:Person找不到copyWithZone:方法。我们将复制副本的代码换成如下:


Person * person2 = [ person1 mutableCopy ]; //复制副本


再次运行程序,程序同样崩溃了,并输出去以下错误信息:


[ Person mutableCopyWithZone : ] : unrecognized selector sent to instance 0x600000221120


上面的提示:Person找不到mutableCopyWithZone:方法。


大家可能会觉得疑惑,程序只是调用了copy和mutableCopy方法,为什么会提示找不到copyWithZone:与mutableCopyWithZone:方法呢?其实当程序调用对象的copy方法来复制自身时,底层需要调用copyWithZone:方法来完成实际的复制工作,copy返回实际上就是copyWithZone:方法的返回值;mutableCopy与mutableCopyWithZone:方法也是同样的道理。


那么怎么做才能让自定义的对象进行copy与mutableCopy呢?需要做以下事情:


1. 让类实现 NSCopying / NSMutableCopying 协议。

2. 让类实现 copyWithZone :/ mutableCopyWithZone : 方法


所以让我们的Person类能够复制自身,我们需要让Person实现NSCopying协议;然后实现copyWithZone:方法:


@ interface Person : NSObject

@ property ( nonatomic , assign ) NSInteger age ;

@ property ( nonatomic , copy







请到「今天看啥」查看全文