记开发中一个问题,关于copy和mutableCopy
2017-06-16 本文已影响57人
思考的快与慢
首先我们先看一段代码,
这是一个模型,里面有四个属性
@interface YCTeacherShowUserInfoModel : NSObject
/** 用户ID */
@property (nonatomic, copy) NSString *_id;
/** 昵称 */
@property (nonatomic, copy) NSString *nickname;
/** 等级 */
@property (nonatomic, assign) NSInteger level;
/** 头像 */
@property (nonatomic, copy) NSString *avatar;
@end
然后进行下面的操作:
YCTeacherShowUserInfoModel *model1 = [[YCTeacherShowUserInfoModel alloc] init];
model1.nickname = @"哈哈1";
model1.avatar = @"图片1";
YCTeacherShowUserInfoModel *model2 = [[YCTeacherShowUserInfoModel alloc] init];
model2.nickname = @"哈哈2";
model2.avatar = @"图片2";
NSArray *normaleArr = @[model1, model2];
NSArray *tempArr = normaleArr;
NSMutableArray *listArray = [NSMutableArray arrayWithArray:tempArr];
[listArray enumerateObjectsUsingBlock:^(YCTeacherShowUserInfoModel *obj, NSUInteger idx, BOOL * _Nonnull stop) {
obj.nickname = @"呵呵呵";
}];
NSLog(@"------%@", normaleArr);
我们来分析一下,这个代码,刚开始的时候,我觉得这个结果,normalArr
数组没有发生变化,但是打印的结果却让我大吃一惊,normalArr
中的模型的nickname
属性都变成了呵呵呵
, 然后通过控制台可以看出
分析一下原因,如下图:
WechatIMG15.jpeg从上面这张图可以看出,为什么我们修改model的属性的值的时候,会改变normal数组中模型的值了。
对于上面这个问题,我们应该怎么解决呢,首先我们分析一下,如何首先分析一下,
- 对于系统的容器类对象,对不可变对象(如 NSArray)进行复制,copy 是指针复制(浅拷贝), mutableCopy 是对象复制(深拷贝), 但是不管是 copy 还是 mutableCopy, 且不论容器内对象是可变还是不可变,返回的容器内对象都是指针复制(浅拷贝)。
- 对于系统的容器类对象,对可变对象(如 NSMutableArray)进行复制时,copy 和 mutableCopy 都是对象复制(深拷贝),但是不管是 copy 还是 mutableCopy,且不论容器内对象是可变还是不可变,返回的容器内对象都是指针复制(浅拷贝)。
基于上面的结论,浅复制,并不拷贝对象本身,仅仅是拷贝指向对象的指针;深复制是直接拷贝整个对象内存到另一块内存中。所以我们应该让对象具备深copy能力,也就是具备copy内容的能力。让对象具备copy能力的前提是让对象遵守 NSCopying
协议,如果让对象同时具备mutableCopy
能力,同样要遵守NSMutableCopying
协议,所以对于YCTeacherShowUserInfoModel来说,应该:
#import "YCTeacherShowUserInfoModel.h"
@interface YCTeacherShowUserInfoModel()<NSCopying, NSMutableCopying>
@end
@implementation YCTeacherShowUserInfoModel
- (id)copyWithZone:(NSZone *)zone {
YCTeacherShowUserInfoModel *user = [[YCTeacherShowUserInfoModel allocWithZone:zone] init];
user._id = self._id;
user.nickname = self.nickname;
user.avatar = self.avatar;
user.level = self.level;
return user;
}
- (id)mutableCopyWithZone:(NSZone *)zone {
YCTeacherShowUserInfoModel *user = [[YCTeacherShowUserInfoModel allocWithZone:zone] init];
user._id = self._id;
user.nickname = self.nickname;
user.avatar = self.avatar;
user.level = self.level;
return user;
}
@end
然后在调用的时候,只需要按照下面的姿势就可以了,就可以实现修改listArray中对象的值的时候,不会影响normalArray中对象的值。
YCTeacherShowUserInfoModel *model1 = [[YCTeacherShowUserInfoModel alloc] init];
model1.nickname = @"哈哈1";
model1.avatar = @"图片1";
YCTeacherShowUserInfoModel *model2 = [[YCTeacherShowUserInfoModel alloc] init];
model2.nickname = @"哈哈2";
model2.avatar = @"图片2";
NSArray *normaleArr = @[model1, model2];
NSMutableArray *listArray = [NSMutableArray array];
for (YCTeacherShowUserInfoModel *model in normaleArr) {
[listArray addObject:model.copy];
}
[listArray enumerateObjectsUsingBlock:^(YCTeacherShowUserInfoModel *obj, NSUInteger idx, BOOL * _Nonnull stop) {
obj.nickname = @"呵呵呵";
}];