NSCopying协议

先来看一段代码

NSMutableArray *arr1 = [[NSMutableArray alloc] initWithObjects:@1, @2, @3, nil]; NSMutableArray *arr2 = arr1; [arr1 removeObjectAtIndex:0];

在删除arr1第一个元素的同时,arr2的第一个元素也被删除了,这很好理解,因为两个对象都指向同一个地址
如果想操作arr1的同时不影响到arr2,则只需改动一句
NSMutableArray *arr2 = [arr1 copy];

如果调用copy方法的对象是自己定义的对象,那么该对象需要实现NSCopying协议
Person.h
@interface Person : NSObject@property(nonatomic, copy) NSString *name; @property(nonatomic, assign) NSInteger age; @end

【NSCopying协议】Person.m
- (id)copyWithZone:(NSZone *)zone { Person *copy = [[[self class] alloc] init]; copy.name = self.name; copy.age= self.age; return copy; }

更复杂的情况
@interface Book : NSObject @property(nonatomic, copy) NSString *name; @property(nonatomic, assign) float price; @end

@interface Person : NSObject @property(nonatomic, copy) NSMutableString *name; @property(nonatomic, strong) Book *book; @end@implementation Person - (id)copyWithZone:(NSZone *)zone { Person *copy = [[[self class] alloc] init]; copy.name = self.name; copy.book = self.book; return copy; }

调用
Book *book = [Book new]; book.name = @"OBJC"; book.price = 89.99; Person *p1 = [Person new]; p1.name = [NSMutableString stringWithString:@"JC"]; p1.book = book; Person *p2 = [p1 copy]; [p2.name appendString:@"Henry"]; //这里会报错(unrecognized selector) p2.book.name = @"JAVA"; p2.book.price = 79.99;

这里需要重点注意下,程序中p2.name明明定义的是NSMutableString类型,为什么会报不存在方法的错误呢?因为在合成gettersetter方法的时候没有提供mutableCopy指示符,因此即使定义实例变量时使用了可变类型,但只要使用copy指示符,实例变量实际得到的值总是不可变对象,系统默认的setter方法如下
- (void)setName:(NSMutableString *)name { _name = [name copy]; }

因此需要在person.m文件中添加如下代码
- (void)setName:(NSMutableString *)name { _name = [name mutableCopy]; }

p2.book任意属性变化也会影响到p1.book的属性
这里需要修改两个地方
  1. Book类实现NSCopying协议
  2. Person.m- (id)copyWithZone:(NSZone *)zone方法中将copy.book = self.book; 替换成copy.book = [self.book copy];

    推荐阅读