上次面試中,面試官問的問題,我總是習慣于使用Copy,但是里面究竟有什么區別,我沒有很好的表達出來,這次通過幾個簡單的測試,直觀的展示Copy和Strong的區別
- 首先分別用strong和copy定義這個兩個NSString類型的屬性sString和cString
@property (nonatomic, strong) NSString *sString;
@property (nonatomic, copy) NSString *cString;
- 然后定義一個不可變類型的字符串的對象,即NSSring對象,然后進行如下賦值,分別輸出他們的指針和內存地址
- (void)test1 {
NSString *testStr1 = @"測試1";
self.sString = testStr1;
self.cString = testStr1;
NSLog(@"%@, %p, %p", testStr1, testStr1, &testStr1);
NSLog(@"%@, %p, %p", _sString, _sString, &_sString);
NSLog(@"%@, %p, %p", _cString, _cString, &_cString);
}
-
輸出結果如下
image.png
結果表明:不管是Strong還是Copy屬性的對象,指向的地址都是testStr1指向的地址。如在MRC環境,輸出testStr1的引用計數,會看到其引用計數值是3,即Strong操作和Copy操作都會使原字符串對象的引用計數值加了1。
- 這次我們定義一個可變類型的字符串對象,即NSMutableString對象,然后進行如下賦值,分別輸出他們的指針和內存地址
- (void)test2 {
NSMutableString *testStr2 = @"測試2".mutableCopy;
self.sString = testStr2;
self.cString = testStr2;
NSLog(@"%@, %p, %p", testStr2, testStr2, &testStr2);
NSLog(@"%@, %p, %p", _sString, _sString, &_sString);
NSLog(@"%@, %p, %p", _cString, _cString, &_cString);
}
-
輸出結果如下
image.png
結果表明:此時Copy屬性字符串已不再指向原來String對象,而是深拷貝了testStr2字符串,且cString對象指向這個字符串。在MRC環境下,輸出兩者的引用計數,可以看到String對象的引用計數是2,而cString對象的引用計數是1。
- 還是定義一個可變類型的字符串對象,即NSMutableString對象,然后進行如下賦值,并且通過appendString來修改testStr3的值,前后分別進行輸出
- (void)test3 {
NSMutableString *testStr3 = @"測試3".mutableCopy;
self.sString = testStr3;
self.cString = testStr3;
NSLog(@"%@, %p, %p", testStr3, testStr3, &testStr3);
NSLog(@"%@, %p, %p", _sString, _sString, &_sString);
NSLog(@"%@, %p, %p", _cString, _cString, &_cString);
NSLog(@"-----------------------------");
[testStr3 appendString:@"_修改"];
NSLog(@"%@, %p, %p", testStr3, testStr3, &testStr3);
NSLog(@"%@, %p, %p", _sString, _sString, &_sString);
NSLog(@"%@, %p, %p", _cString, _cString, &_cString);
}
-
輸出結果如下
image.png
結果表明:修改原始可變字符串testStr3話,可以看到,因為sString與原始testStr3是指向同一對象,所以sString的值也會跟隨testStr3改變(此時sString的類型實際上是NSMutableString,而不是NSString),而cString是指向另一個對象,并不會改變。
最后結論
-
NSMutableString
是NSString
的子類,一個NSString
指針可以指向NSMutableString
對象,即父類對象指向子類類型 - 當原字符串是
NSString
時,字符串是不可變的,不管是Strong
還是Copy
屬性的對象,都是指向原對象,Copy
操作只是做了次淺拷貝 - 當原字符串是
NSMutableString
時,Strong
屬性只是增加了原字符串的引用計數,而Copy
屬性則是對原字符串做了次深拷貝,產生一個新的對象,且Copy
屬性對象指向這個新的對象,且這個Copy
屬性對象的類型始終是NSString
,而不是NSMutableString
,因此其是不可變的 - 性能問題:即在原字符串是
NSMutableString
,Strong
是單純的增加對象的引用計數,而Copy
操作是執行了一次深拷貝,所以性能上會有所差異(雖然不大)。如果原字符串是NSString
時,則沒有這個問題 - 經驗總結:所以,在聲明
NSString
屬性時,到底是選擇strong
還是copy
,可以根據實際情況來定,不過,一般我們將對象聲明為NSString
時,都不希望它改變,所以大多數情況下,我們建議用copy,以免因可變字符串的修改導致的一些非預期問題