iOS 关于数组深拷贝 initWithArray:copyItems: 方法的讨论

包含有对象类型的数组。无论可变还是不可变,通过copy,mutableCopy都不能将数组内的model完全copy一份,虽然得到的数组是新的,但数组中model的指针指向的还是之前的model。此时,如果改变了数组中model的值,原数组会受到影响。

    Person * a = [Person new];
    a.name = @"a";
    a.gender = @"male";
    
    Person * b = [Person new];
    b.name = @"b";
    b.gender =@"female";
    
    NSMutableArray *mutA = [NSMutableArray arrayWithObjects:a,b, nil];
    NSMutableArray *mutB = [mutA mutableCopy];
    
    Person *c = mutB.firstObject;
    c.name = @"c";
    c.gender = @"female";
iOS 关于数组深拷贝 initWithArray:copyItems: 方法的讨论_第1张图片
exOne.jpg

如果对象是单层的(没有嵌套的模型),此时,model遵循NSCopying,NSMutableCopying协议,实现copyWithZone和mutableCopyWithZone方法。

- (id)copyWithZone:(NSZone *)zone{
    Person *person = [[Person allocWithZone:zone] init];
    person.name = self.name;
    person.gender = self.gender;
    return person;
}

- (id)mutableCopyWithZone:(NSZone *)zone{
    Person *person = [[Person allocWithZone:zone] init];
    person.name = self.name;
    person.gender = self.gender;
    return person;
}

Array通过 initWithArray:copyItems: 方法可以得到一个完全拷贝过的数组(数组内的model也是全新的model)。

    NSMutableArray *mutB = [[NSMutableArray alloc] initWithArray:mutA copyItems:YES];
iOS 关于数组深拷贝 initWithArray:copyItems: 方法的讨论_第2张图片
exTwo.jpg

但是!!

如果数组内的model有嵌套,例如

   @interface Person : NSObject

    @property (nonatomic, strong) NSString *name;

    @property (nonatomic, strong) Gender *gender;

    @end
    Person * a = [Person new];
    a.name = @"a";
    Gender *agender = [Gender new];
    agender.title = @"male";
    a.gender = agender;
    
    Person * b = [Person new];
    b.name = @"b";
    Gender *bgender = [Gender new];
    bgender.title =@"female";
    b.gender = bgender;
    
    NSMutableArray *mutA = [NSMutableArray arrayWithObjects:a,b, nil];
    NSMutableArray *mutB = [[NSMutableArray alloc] initWithArray:mutA copyItems:YES];
    
    Person *c = mutB.firstObject;
    c.name = @"c";
    c.gender.title = @"female";
iOS 关于数组深拷贝 initWithArray:copyItems: 方法的讨论_第3张图片
exThree.jpg

可以看出,改动B数组中的firstObject,A中的name没有跟着改变,但A中的gender发生了变化。

接下来再试一下,gender类也遵循NSCopying,NSMutableCopying协议。看下是什么效果。

- (id)copyWithZone:(NSZone *)zone{
    Gender *gender = [[Gender allocWithZone:zone] init];
    gender.title = self.title;
    return gender;
}

- (id)mutableCopyWithZone:(NSZone *)zone{
    Gender *gender = [[Gender allocWithZone:zone] init];
    gender.title = self.title;
    return gender;
}
iOS 关于数组深拷贝 initWithArray:copyItems: 方法的讨论_第4张图片
exFour.jpg

如上图所示,依然不能满足要求。

此时。需要你在copyWithZone方法中,new一个新的Gender对象(newGender),将person的gender各个属性的值,手动赋值给这个newGender。再将newGender赋值给person。

    Person *person = [[Person allocWithZone:zone] init];
    Gender *newGender = [Gender new];
    newGender.title = self.gender.title;
    person.gender = newGender;
    return person;

其实,person遵循NSCopying协议,系统会帮你去调用copyWithZone,但是copyWithZon具体的实现,还是你自己决定的。就相当于自己手动new了一个新对象,然后赋值,最后把这个新对象return出来。 跟你自己在工具类中,写一个model间数据转化的方法是一个道理。

归档接归档。

将A数组序列化为一个Data,再将Data解归档为一个新的数组。此时的数组就是一个全新的数组。

[NSKeyedArchiver archivedDataWithRootObject:object]
[NSKeyedUnarchiver unarchiveObjectWithData:data]

person和gender类都需要遵循NSCoding协议,实现initWithCoder 和 encodeWithCoder方法。


iOS 关于数组深拷贝 initWithArray:copyItems: 方法的讨论_第5张图片
exSix.jpg

再试一次, bingo!


iOS 关于数组深拷贝 initWithArray:copyItems: 方法的讨论_第6张图片
exFive.jpg

你可能感兴趣的:(iOS 关于数组深拷贝 initWithArray:copyItems: 方法的讨论)