结论
- 对于copy修饰的属性来说,若赋值源是NSString、NSArray、NSURLRequest三者其中之一,复制时是shallow copy(浅复制),即地址相同,类型相同。
- 一般情况下,NSString使用copy修饰。即:
@property (nonatomic, copy) NSString *string;
解释说明
结论1
首先,需要知道
copy和strong对应的所有权修饰符都是 __strong。
strong修饰的属性,赋值后,地址相同,类型相同。
copy修饰的属性,赋值时,通过 NSCopying 接口的 copyWithZone: 方法复制赋值源所生成的对象,赋值后,地址不一定相同,类型不一定相同。
而复制分为shallow copy与deep copy,区别如下:
shallow copy 即浅复制,没有产生新对象,指针指向原来对象。
deep copy 即深复制,产生新对象。
接着,Show the code
String相关属性
@property (nonatomic, strong) NSString *strongString; /**<strong string*/
@property (nonatomic, strong) NSMutableString *mStrongString; /**<strong mutable string*/
@property (nonatomic, copy) NSString *cString; /**<copy string*/
@property (nonatomic, copy) NSMutableString *mCopyString; /**<copy mutable string*/
对String的测试
- (void)stringTest {
//来源是NSString
NSString *string = @"string";
NSLog(@"address: %p | class: %@ of string",string,[string class]);
self.strongString = string;
self.cString = string;
self.mStrongString = string;
self.mCopyString = string;
[self printStringInfo];
NSLog(@"\n");
//来源是NSMutableString
NSMutableString *mutableString = [NSMutableString stringWithString:@"mutable string"];
NSLog(@"address: %p | class: %@ of mutable string",mutableString,[mutableString class]);
self.strongString = mutableString;
self.cString = mutableString;
self.mStrongString = mutableString;
self.mCopyString = mutableString;
[self printStringInfo];
}
- (void)printStringInfo {
NSLog(@"address: %p | class: %@ of strong string",self.strongString,[self.strongString class]);
NSLog(@"address: %p | class: %@ of copy string",self.cString,[self.cString class]);
NSLog(@"address: %p | class: %@ of strong mutable string",self.mStrongString,[self.mStrongString class]);
NSLog(@"address: %p | class: %@ of copy mutable string",self.mCopyString,[self.mCopyString class]);
}
(注:以上是只有部分代码,想了解更多,请查看文章底部的源代码)
然后,分别打印来源是NSString、NSArray、NSURLRequest的运行结果:
来源是NSString 来源是NSArray 来源是NSURLRequest对比以上3张图中的地址及类型,可知:
来源是NSString、NSArray、NSURLRequest三者之一的,使用strong或copy修饰的,赋值结果都是一样的,可证明结论1:
对于copy修饰的属性来说,若赋值源是NSString、NSArray、NSURLRequest三者其中之一,复制时是shadow copy(浅复制),即地址相同,类型相同。
结论2
分别打印来源是NSMutableString、NSMutableArray、NSMutableNSURLRequest的结果:
来源是NSMutableString 来源是NSMutableArray 来源是NSMutableNSURLRequest
对比以上3张图中的地址及类型,可知:
来源若是NSMutableString,NSMutableArray,NSMutableURLRequest之一
- 使用strong修饰的,赋值后,地址相同,类型也相同。
- 使用copy修饰的,会复制赋值源所生成的对象,复制后,地址不同,而来源是NSMutableArray的,甚至连类型也不同(
__NSArrayI
与__NSArrayM
),说明复制时都是deep copy(深复制)。
(据了解,copy除了复制NSString、NSArray、NSURLRequest外,其他都是deep copy。)(未知真实性)
也就是说:
如果来源是NSString,使用copy或strong没有区别。
如果来源是NSMutableString,NSString对象会因其改变而改变。若使用copy
,因为是深复制,产生了一个新的对象,就可以避免以上情况。
而一般使用NSString变量时,并不希望它可变,Objective-C的类型确定又是在运行时才决定的,那么赋值时,很可能会搞错赋值源的类型:NSMutableString误当作NSString,这样也许会带来不可预知的问题,而且此类问题一般不易察觉,所以可说明结论2:
一般情况下,NSString使用copy修饰。
当然,具体情况,具体分析,使用strong也无可厚非。
附录:剩余的主要代码
Array相关属性
@property (nonatomic, strong) NSArray *strongArray; /**<strong array*/
@property (nonatomic, strong) NSMutableArray *mStrongArray; /**<strong mutable array*/
@property (nonatomic, copy) NSArray *cArray; /**<copy array*/
@property (nonatomic, copy) NSMutableArray *mCopyArray; /**<copy mutable array*/
URL Request相关属性
@property (nonatomic, strong) NSURLRequest *strongRequest; /**<strong request*/
@property (nonatomic, strong) NSMutableURLRequest *mStrongRequest; /**<strong mutalbe request*/
@property (nonatomic, copy) NSURLRequest *cRequest; /**<copy request*/
@property (nonatomic, copy) NSMutableURLRequest *mCopyRequest; /**<copy mutable request*/
对Array的测试
- (void)arrayTest {
//来源是NSArray
NSArray *array = @[ @"item1",@"item2"];
NSLog(@"address: %p | class: %@ of array",array,[array class]);
self.strongArray = array;
self.cArray = array;
self.mStrongArray = array;
self.mCopyArray = array;
[self printArrayInfo];
NSLog(@"\n");
//来源是NSMutableArray
NSMutableArray *mutableArray = [NSMutableArray arrayWithArray:array];
NSLog(@"address: %p | class: %@ of mutable array",mutableArray,[mutableArray class]);
self.strongArray = mutableArray;
self.cArray = mutableArray;
self.mStrongArray = mutableArray;
self.mCopyArray = mutableArray;
[self printArrayInfo];
}
- (void)printArrayInfo {
NSLog(@"address: %p | class: %@ of strong array",self.strongArray,[self.strongArray class]);
NSLog(@"address: %p | class: %@ of copy array",self.cArray,[self.cArray class]);
NSLog(@"address: %p | class: %@ of strong mutable array",self.mStrongArray,[self.mStrongArray class]);
NSLog(@"address: %p | class: %@ of copy mutable array",self.mCopyArray,[self.mCopyArray class]);
}
对URL Request的测试
- (void)urlRequestTest {
//来源是NSURLRequest
NSURL *url = [NSURL URLWithString:@"http://www.baidu.com"];
NSURLRequest *urlRequest = [NSURLRequest requestWithURL:url];
NSLog(@"address: %p | class: %@ of url request",urlRequest,[urlRequest class]);
self.strongRequest = urlRequest;
self.cRequest = urlRequest;
self.mStrongRequest = urlRequest;
self.mCopyRequest = urlRequest;
[self printRequestInfo];
NSLog(@"\n");
//来源是NSMutableURLRequest
NSMutableURLRequest *mutableURLRequest = [NSMutableURLRequest requestWithURL:url];
NSLog(@"address: %p | class: %@ of mutable request",mutableURLRequest,[mutableURLRequest class]);
self.strongRequest = mutableURLRequest;
self.cRequest = mutableURLRequest;
self.mStrongRequest = mutableURLRequest;
self.mCopyRequest = mutableURLRequest;
[self printRequestInfo];
}
- (void)printRequestInfo {
NSLog(@"address: %p | class: %@ of strong request",self.strongRequest,[self.strongRequest class]);
NSLog(@"address: %p | class: %@ of copy request",self.cRequest,[self.cRequest class]);
NSLog(@"address: %p | class: %@ of strong mutable equest",self.mStrongRequest,[self.mStrongRequest class]);
NSLog(@"address: %p | class: %@ of copy mutable request",self.mCopyRequest,[self.mCopyRequest class]);
}
网友评论
比如现分别有 用copy和strong修饰的属性
@property (copy, nonatomic) NSString *copyName;
@property (strong, nonatomic) NSString *strongName;
通过setter分别对其赋值一个NSMutableString对象 mutableName时
self.copyName = mutableStr --> 该setter方法 内会对 [mutableName copy]操作
self.strongName = mutableStr --> 而该setter 就直接将一个NSMutableString对象的地址赋给了strongName指针变量
所以当 mutableName的内容 改变时 , self.strongName也会发生变化, 而copyName就不会. 这种bug找起来会很蛋疼的