Copy (一)

在 iOS 开发中经常会用到 copy 关键字,主要的应用方面就是 @property 属性的修饰。这篇文章主要关心:

数组(NSArray、NSMutableArray)与 copy

NSMutableArray 作为属性该使用 strong 还是 copy 修饰?

1
2
3
4
5
6

@interface Person : NSObject

@property (nonatomic, copy) NSMutableArray *catNames;

@end

比如,这里有个 Person 类,有一个属性是 catNames,用于存放猫的名字, 我们使用:

1
2
3
Person *p = [Person new];
p.cats = [NSMutableArray arrayWithCapacity:10];
[p.cats addObject:@"Tom"];

这段程序运行的结果是:

1
2018-07-24 12:51:11.928550+0800 CopyDemo[5781:3493921] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSArray0 addObject:]: unrecognized selector sent to instance 0x60400000cdc0'

crash 了!!!

为什么会 Crash 呢?
首先,crash 的语言是找不到方法(unrecognized selector sent to instance)。
其次,我们通过 @property (nonatomic, copy) NSMutableArray *catNames; 做了什么,是让系统自动为我们生成了 setter 和 getter 方法,而 copy 就控制着这些方法的生成细节。如果不修改这段声明的话,可以在 Person 的实现中修改 setter 方法的实现:

1
2
3
- (void)setCats:(NSMutableArray *)cats {
_cats = [cats mutableCopy];
}

或者

1
2
3
- (void)setCats:(NSMutableArray *)cats {
_cats = cats;
}

本质就是:一个 NSMutableArray 的对象,经过 copy 方法生成对象其实是一个 NSArray 对象,也就是上面 p.cats = [NSMutableArray arrayWithCapacity:10]; 赋值运算符左侧其实是一个不可变数组了,而右侧是可变数组。

综上,针对于可变数组,我们使用 strong 来进行修饰,不用 copy。

NSArray 作为属性该使用 strong 还是 copy 修饰?

上面已经说明了,针对 NSMutableArray 我们使用 strong 来进行修饰,那么 NSArray 呢?

首先,我们来看一下,使用 strong 来修饰,会怎样?

1
2
3
4
5
6

@interface Person : NSObject

@property (nonatomic, strong) NSArray *phones;

@end

为 Person 类添加了属性 phones,标识当前人对象拥有的手机,从 API 的定义可以看出,是不可变数组,所以当我们为这个人对象设置了 phones 属性之后,我们不希望手机数量会发生变化,接下来看是具体使用:

1
2
3
4
5
6
7
8
- (void)addPhones {

Person *p = [Person new];
NSMutableArray *phones = [NSMutableArray arrayWithObjects:@"iPhone 5s",@"iPhone 6", nil];
p.phones = phones;// 多态 p.phones = @[@"iPhone 5s",@"iPhone 6"];
[phones addObject:@"iPhone 6s"];
NSLog(@"%@",p.phones);//("iPhone 5s","iPhone 6","iPhone 6s")
}

从上面可以看出,如果我们通过 strong 来进行修饰的话,就不能空着 NSArray 的不可变性了,所以对于 NSArray 我们使用 copy 来修饰会更好一些,这样可以保证类属性的封装性。

-------------本文结束谢谢欣赏-------------
Alice wechat