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<NSCoding, NSCopying>

@property(nonatomic, copy) NSString *name;
@property(nonatomic, assign) NSInteger age;

@end

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<NSCopying>
@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];
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容