1.strong和copy的區(qū)別
通常情況下,我們在定義字符串屬性的時候,會用到兩種修飾詞:strong和copy。但是比較規(guī)范的寫法是用copy,也就是說copy要比strong更好,到底copy好在哪里?我們下面用實例來說明。
@interface ViewController ()
@property (nonatomic, copy) NSString* str1;
@property (nonatomic, strong) NSString* str2;
@end
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
NSMutableString* tempStr = [@"hello" mutableCopy];
self.str1 = tempStr;
self.str2 = tempStr;
NSLog(@"str1 = %@, str2 = %@",self.str1, self.str2);
[tempStr appendFormat:@"world"];
NSLog(@"str1 = %@, str2 = %@",self.str1, self.str2);
}
在上面的代碼中,分別給str1和str2賦值為同一個可變字符串變量(有人可能會疑問,為什么要賦一個可變字符串,而不是一個NSString類型的?如果賦值一個NSString類型的字符串,用strong和copy也就沒有什么區(qū)別了,這一點我們后面會進行總結(jié),在這兒我們先看它們之間的差異),執(zhí)行上面的代碼,打印的結(jié)果如下圖:

通過打印的結(jié)果我們發(fā)現(xiàn):當我改變tempStr的值的時候,str1的值沒有發(fā)生變化(這個是用copy修飾的), 但是str2的值發(fā)生了改變(這個是用strong修飾的),由此我們可以假設(shè)一下,str1和tempStr不是指向同一塊兒內(nèi)存,而str2和tempStr指向同一塊兒內(nèi)存,下面來驗證一下:
NSMutableString* tempStr = [@"hello" mutableCopy];
self.str1 = tempStr;
self.str2 = tempStr;
NSLog(@"temStr = %p, self.str1 = %p, self.str2 = %p",tempStr,self.str1,self.str2);
NSLog(@"str1 = %@, str2 = %@",self.str1, self.str2);
[tempStr appendFormat:@"world"];
NSLog(@"str1 = %@, str2 = %@",self.str1, self.str2);
只是在原來的代碼中加了一行指針打印,打印結(jié)果如下:

果然和我們假設(shè)的一致,str1和tempStr不指向同一塊兒內(nèi)存,而str2和tempStr指向了同一塊兒內(nèi)存。那么這樣就會出現(xiàn)一個問題:本來我們定義的str2是一個NSString類型,這就意味著我們并不想str2發(fā)生改變,但是當外界賦給它一個可變的值的時候,它卻因為外界值的修改而被修改,這是我們所不愿看到的。所以上面的情況用copy修飾會更好。
2.NSArray是不是也需要用copy來修飾?
看了上面的情況,是不是有人會聯(lián)想到像 NSArray和NSDictionary這樣的可以賦給一個可變量的屬性,是不是也應(yīng)該用copy來修飾?下面我們還是用實例來說明。
@interface ViewController ()
@property (nonatomic, copy) NSArray* array1;
@property (nonatomic, strong) NSArray* array2;
@end
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
NSMutableArray* tempArray = [@[@"hello"] mutableCopy];
self.array1 = tempArray;
self.array2 = tempArray;
NSLog(@"tempArray = %p, array1 = %p, array2 = %p, ",tempArray,self.array1,self.array2);
NSLog(@"array1 = %@, array2 = %@",self.array1,self.array2);
[tempArray addObject:@"world"];
NSLog(@"array1 = %@, array2 = %@",self.array1,self.array2);
}
打印結(jié)果如下:

從打印的結(jié)果我們依然可以得出: array1(也就是用copy修飾的)和tempArray不指向同一塊兒內(nèi)存,array2(也就是用strong修飾的)和tempArray指向了同一塊兒內(nèi)存,所以當我們修改tempArray的時候,array2的值也被修改了,這跟我們上面定義成NSArray,也就是不可變類型相違背,所以當我們定義一個像NSArray和NSDictionary這樣有對應(yīng)可變類型的屬性的時候,都應(yīng)該用copy。
可能到這兒還是有人有疑問,如果我定義的屬性本身就是一個可變類型的,比如NSMutableArray,那么我是應(yīng)該用strong還是copy呢?如果不出意料的話,大家用的都是strong,下面我們測一下為什么strong又比copy好。還是用實例說話。
@interface ViewController ()
@property (nonatomic, copy) NSMutableArray* array3;
@property (nonatomic, strong) NSMutableArray* array4;
@end
- (void)viewDidLoad {
[super viewDidLoad];
NSMutableArray* tempArray = [NSMutableArray arrayWithObject:@"hello"];
self.array3 = tempArray;
self.array4 = tempArray;
NSLog(@"tempArray = %p,array3 = %p,array4 = %p",tempArray,self.array3,self.array4);
[tempArray addObject:@"world"];
NSLog(@"array3 = %@,array4 = %@,",self.array3,self.array4);
}
打印的結(jié)果如下:

從打印的結(jié)果可以看出,array3和tempArray不是指向同一塊兒內(nèi)存,array4和tempArray指向同一塊兒內(nèi)存,所以當修改tempArray的值的時候,array4的值也跟著改了。而array4本身就是一個NSMutableArray類型,就意味著是可以被修改的,所以用strong會更好。
-
總結(jié)一下上面的類容
用copy還是strong主要取決于開發(fā)者的意圖:當你不允許讓這個屬性的值被外界更改,就用copy;當你允許這個屬性的值被外界所更改,就用strong。
3. copy和mutablecopy
對于copy和mutablecopy的區(qū)別,需要分為兩種情況來談:給不可變屬性賦值和給可變屬性賦值。下面先看給不可變屬性賦值的情況,依然用實例說話:
@interface ViewController ()
@property (nonatomic, copy) NSString* str3;
@end
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
NSString* tempStr = @"hello";
self.str3 = [tempStr copy];
NSLog(@"tempStr_p1 = %p, str3_p1 = %p",tempStr,self.str3);
self.str3 = [tempStr mutableCopy];
NSLog(@"tempStr_p2 = %p, str3_p2 = %p",tempStr,self.str3);
}
打印結(jié)果如下:

- 由圖打印的結(jié)果可以得出如下結(jié)論
str3是不可變的類型,[tempStr copy]也是不可變的類型,把tempStr賦給str3,也就是把一個不可變的賦給一個不可變的,既然兩個都不可變,也就是都不存在被修改的風(fēng)險,所以用同一塊兒內(nèi)存就行了,沒有必要再搞一塊兒內(nèi)存,所以會有上面的 tempStr_p1=str3_p1;
但是[tempStr mutableCopy]是一個可變的類型,把[tempStr mutableCopy]賦給str3,也就是把一個可變的賦給了一個不可變的,但是這樣就會出現(xiàn)一個問題:當可變的那個變量的值發(fā)生改變的時候,可能會導(dǎo)致不可變的那個變量的值也跟著改變,這就違背了開發(fā)者的意圖,所以就要給str3重新分配一份兒內(nèi)存,也就有了上面的 tempStr_p12 != str3_p2。
下面再看看給可變類型的屬性賦值的情況,還是用實例說話:
@interface ViewController ()
@property (nonatomic, strong) NSMutableString* str4;
@end
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
NSMutableString* tempStr = [NSMutableString stringWithString:@"hello"];
self.str4 = [tempStr copy];
NSLog(@"tempStr_p1 = %p, str4_p1 = %p",tempStr,self.str4);
self.str4 = [tempStr mutableCopy];
NSLog(@"tempStr_p2 = %p, str4_p2 = %p",tempStr,self.str4);
}
打印結(jié)果如下圖

由圖打印的結(jié)果可以得出如下的結(jié)論
str4是可變的類型,[tempStr copy]其實是一個不可變的類型,把[tempStr copy]賦給str4,其實是把一個不可變的賦給了一個可變的,如果這兩個還共用一塊兒內(nèi)存的話,當str4的值發(fā)生了改變,會導(dǎo)致[tempStr copy]這個不可變的變量的值也跟著變化,這樣就矛盾了,所以就有了上面的 tempStr_p1 != str4_p1,也就是給str4重新搞一塊兒內(nèi)存,讓str4在自己的那塊兒內(nèi)存中隨便折騰而不影響別人;
但是[tempStr mutableCopy]是一個可變的類型,把[tempStr mutableCopy]賦給str4,其實是把一個可變的賦給了一個可變的,那么可能有人會有疑問,既然都是可變的,那為何不共用同一塊兒內(nèi)存呢,為何 tempStr_p2 != str4_p2呢?我的理解是這樣的:雖然[tempStr mutableCopy]是可變的,但是我不希望你str4來改變我,我要變我自己會變,所以還是給str4搞了一塊兒新的內(nèi)存,讓str4自己玩自己的,不要去影響別人。本文屬原創(chuàng)文章,轉(zhuǎn)載請注明出處,謝謝!