天天看點

iOS之copy、strong使用,block特性

什麼時候使用copy,即修飾NSString類型與block,其他的都是使用strong關鍵字修飾。說到這裡,我們先來

說說NSString類型,我在建立的NSString類型的屬性中,也曾也使用過strong修飾的,因為我幾乎沒有使用過NSMutableString類型轉換,我不用去考慮是用copy還是strong更好,當然為了代碼的健壯使用copy更好,以下我就作具體分析緣由。

在MRC中,使用retain,copy進行拷貝,會使retainCount結果+1.但是如果是深拷貝,便會改變指針,retainCount = 1;下面我直接在ARC下調試,我隻關心記憶體指針,不關心retainCount。

NSString *str0 = @"a";

    NSLog(@"str0記憶體位址: %p",str0);    //0x107fcb088   在64位系統上得到的記憶體位址較短,說明存放在常量區(代碼,常量,全局,堆,棧)

    NSString *string0  = [str0 copy];

    NSLog(@"string0的記憶體位址: %p",string0);   //0x107fcb088  淺拷貝



    NSString *str = [NSString stringWithFormat:@"%@",@"a"];

    NSLog(@"str記憶體位址: %p",str);   //0xa000000000000611  (棧區)

    NSString *string  = [str copy];

    NSLog(@"string的記憶體位址: %p",string);   //0xa000000000000611  淺拷貝



    NSMutableString *str1 = [NSMutableString stringWithFormat:@"a"];

    NSLog(@"str1的記憶體位址:%p",str1);   //0x60000007c5c0

    NSMutableString *string1 = [str1 copy];

    NSLog(@"string1的記憶體位址: %p",string1);   //0xa000000000000611   記憶體位址發生了改變,進行了深拷貝,而且跟上面的位址一樣
           

總結:對于NSString類型隻是引用了記憶體,淺拷貝;NSMutableString作為NSString的子類進行copy才是深拷貝。

剛剛上面的深拷貝,出現跟淺拷貝一樣的位址,不由得我們需要多做兩個測試,如下:

NSMutableString *strEx = [str mutableCopy];

    NSLog(@"strEx的記憶體位址:%p",strEx);    //0x608000263040 深拷貝

    NSMutableString *strExCopy = [str mutableCopy];

    NSLog(@"strExCopy的記憶體位址:%p",strExCopy); //0x60000026a440    str兩次mutableCopy的位址不一樣

     NSMutableString *stringEx = [strEx copy];

    NSLog(@"stringEx的記憶體位址: %p",stringEx);   //0xa000000000000611 與上面位址一樣

   NSMutableString *stringEx1 = [strExCopy copy];

    NSLog(@"stringEx1的記憶體位址: %p",stringEx1); //這個也是0xa000000000000611,說明兩次copy都指向同一個位址

    NSMutableString *strExEx = [strEx mutableCopy];

    NSLog(@"strExEx的記憶體位址:%p",strExEx);     //0x600000073d00 深拷貝
           

結論:可以看成,str1所謂的“深拷貝”,其實不是“深拷貝”,它還是拷貝了之前的位址。這樣,我得出,當進行mutable建立,其實是系統首先建立了一份NSString的位址,然後再深拷貝,相當于[NSMutableString stringWithFormat:@”a”];來自于 [str mutableCopy];。

在字元串類型NSString中使用strong還是copy,到底哪個更好,蘋果自己的API中告訴了我,copy更好,那麼我們就進一步進行驗證。首先我們建立兩個字元串對象分别為strong與copy修飾的,然後再進行指派比較,如下。

@property (strong,nonatomic)NSString *testStr;

@property (copy,nonatomic)NSString *testStrCopy;

- (void)viewDidLoad {

    [super viewDidLoad];

   NSString *testStr = [NSString stringWithFormat:@"%@",@"a"]; 

    NSLog(@"testStr記憶體位址: %p",testStr); //0xa000000000000611

    self.testStr = testStr;

    NSLog(@"self.testStr記憶體位址: %p",self.testStr);//0xa000000000000611   淺拷貝

    self.testStrCopy = testStr;

    NSLog(@"self.testStrCopy記憶體位址: %p",self.testStrCopy);//0xa000000000000611  淺拷貝

    NSMutableString *testStr1 = [NSMutableString stringWithFormat:@"%@",@"a"];

    NSLog(@"testStr1記憶體位址: %p",testStr);  //0x608000078a00  與上面的str1 0x60000007c5c0也不一樣,MutableCopy是重新建立了位址

    self.testStr = testStr1;

    NSLog(@"self.testStr記憶體位址: %p",self.testStr);//0x608000078a00 strong指向同一個位址

    self.testStrCopy = testStr1;

    NSLog(@"self.testStrCopy記憶體位址: %p",self.testStrCopy);//0xa000000000000611 雖然位址變了,但還是指向原來的位址

} 
           

總結:對于NSString類型,使用copy修飾,不會改變它原有的類型,strong會指向引用的對象,有可能改變其類型狀态,是以copy能增強NSString的健壯性。

block特性

另一個使用copy的地方就是修飾block,對于我們現在都使用ARC模式來說,我覺得使用strong或者copy都是可以的,下面用事例說明:

@property (nonatomic,copy)void(^demoBolck)();
@property (nonatomic,strong)void(^demoBolck1)();

int b=;

void (^demoBolck)() = ^{

        NSLog(@"demoBolck");

    };

    NSLog(@"demoBolck %@",demoBolck);    //<__NSGlobalBlock__: 0x1085af0e0>  無論ARC還是MRC下,因不通路外部局部(包括無外部變量或者隻有全局變量),NSGlobalBlock表示在全局區

void (^demoBolck4)() = ^{

        NSLog(@"demoBolck4  %d",b);

    };

   NSLog(@"demoBolck4 %@",demoBolck4);    //<__NSGlobalBlock__: 0x10150b120>  全局區
    __block int a = ;   //block内部引用a,并修改其值,需要用block修飾,不然可以不用。不過是引用行屬性,需要

    void (^demoBolck2)() = ^{
        NSLog(@"demoBolck2 %d",a++);
    };

    demoBolck2();

    NSLog(@"demoBolck2 %@,%d",demoBolck2,a);   //<__NSMallocBlock__: 0x600000056c50> ARC下堆區  <__NSStackBlock__: 0x7fff5d0ada28>MRC下在棧區

    NSLog(@"demoBolck2.Copy %@",[demoBolck2 copy]);    //<__NSMallocBlock__: 0x600000056c50>copy操作不管MRC或者ARC都在堆區,隻是在MRC下進行copy會改變位址

    self.demoBolck = demoBolck2;

    NSLog(@"self.demoBolck %@",self.demoBolck);
    self.demoBolck1 = demoBolck2;
    self.demoBolck1();     //demoBolck2  7   能執行無問題

    NSLog(@"self.demoBolck1 %@",self.demoBolck1);     //<__NSMallocBlock__: 0x600000056c50>  strong修飾并沒有問題
           

總結:在 Objective-C 語言中,一共有 3 種類型的 block:

_NSConcreteGlobalBlock 全局的靜态 block,不會通路外部局部變量。

_NSConcreteStackBlock 儲存在棧中的 block,當函數傳回時會被銷毀。

_NSConcreteMallocBlock 儲存在堆中的 block,當引用計數為 0 時會被銷毀。