iOS中如果想复制一个对象可以使用copy成员方法或者mutablecopy方法,这两个方法是NSObject类的成员方法。这两个方法在使用中是有所区别的。
打个比方说如果要复制一个NSArray对象,如果使用copy方法,则拷贝出一个NSArray对象,如果使用mutablecopy则复制出一个NSMutableArray对象。因此,总结一句话就是:copy总是拷贝出一个不可变的对象,而mutablecopy总是拷贝出可变的对象。
应该注意的是,如果是不可变对象调用copy方法,则拷贝出的对象也是不可变的,因此iOS规定:这种情况下的对象不进行复制,而是仅仅是多了一个指向这个对象的指针,对象的引用计数+1.这种情况叫做浅复制。其他的情况,例如可变复制为可变,可变复制为不可变,不可变复制为可变的情况都是将源对象复制一个副本,这个副本可变不可变由调用的方法决定。这种情况叫做深复制。
上面的举例使用的是系统自带的NSArray,所有系统自带的对象都可以进行copy或者mutablecopy,而且不用去手动实现这两个方法。但平时我们自己创建的类也要进行复制,这时候我们就要对自定义的对象进行copy或者mutablecopy操作,而这个时候我们就需要手动实现这两个方法。
想要让自定义类能够实现copy方法,需要让自定义的类实现<copying>协议,当然如果想使用mutablecopy方法则需要实现<mutablecopying>协议。那copying协议说吧,这个协议中只有一个函数,就是copyWithZone方法。我们需要首先在自己定义的类的实现文件中重写这个方法。假如我们创建的自定义类名是:Student,它含有一个name属性,则这个方法应该大体如下实现:
- (id)copyWithZone:(NSZone *)zone {
Student * stu = [ [ [ self class ] allocWithZone : zone ] init ] ;
stu . name = self . name ;
return stu ;
}
这个方法有一个地方很容易出错,那就是allocWithZone:方法的调用者不是Student而是[self class],为什么要这么写呢?
如果写具体的类,在上面的例子中就是Student,则此处就会开辟Student对象的内存,而如果还有别的类继承这个类,例如又进一步延伸出一个类叫做GoodStudent类继承Student类,那么在复制GoodStudent的时候首先调用父类的方法,则父类方法创建了一个Student,这时候子类比父类多出来的一些属性就不能使用了,因为创建的是一个父类而不是子类,父类不能识别子类独有的属性。改为self class则当子类调用这个方法的时候,self是子类本身,这时候创建出的对象是子类对象,就可以识别子类的属性了。
另外,在编程中发现,千万不要再description方法中打印self,因为这样会导致死循环,因为打印self本身又一次调用了description方法。