大話strong, copy和mutablecopy

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é)果如下圖:


屏幕快照 2016-08-23 10.04.02 AM.png

通過打印的結(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é)果如下:

屏幕快照 2016-08-23 10.33.25 AM.png

果然和我們假設(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é)果如下:

屏幕快照 2016-08-23 10.50.51 AM.png

從打印的結(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é)果如下:

屏幕快照 2016-08-23 11.19.49 AM.png

從打印的結(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é)果如下:

屏幕快照 2016-08-23 6.18.58 PM.png
  • 由圖打印的結(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é)果如下圖

屏幕快照 2016-08-23 6.50.15 PM.png
  • 由圖打印的結(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)載請注明出處,謝謝!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容