iOS block的一些理解和注意點

block的定義:帶有自動變量(局部變量)的匿名函數。

一.block作為參數使用時應該使用copy來修飾。

原因1:當用weak,assign修飾block屬性時,block訪問外部變量,此時block的類型就是棧(stack)block。保存在棧中的block,當block所在函數方法返回結束,該block就會被銷毀。在其他方法內部調用該block,就會引發野指針錯誤EXC_BAD_ACCESS。

原因2.當使用copy,strong修飾block屬性時,block訪問外部變量,此時block的類型時堆(heap)block。保存在堆中的block,當引用計數器為0時被銷毀,該類型block是由棧類型的block從棧中復制到堆中形成的,因此可以在其他方法調用該block。在ARC下,strong和copy都可以修飾block,但是建議修飾block屬性使用copy。

二.block的3種類型

1.不管在ARC還是MRC環境下,block內部如果沒有訪問外部變量,這個block是全局block__NSGlobalBlock__,形式類似函數,存儲在內存中的代碼區。

2.在ARC下,block內部如果訪問外部變量,這個block是堆(heap)block__NSMallocBlock__,存儲在內存中的堆上,因為在ARC下,默認對block做了一次copy操作。

3.在MRC下,block內部如果訪問外部變量,這個block是棧(stack)block__NSStackBlock__,存儲在內存中的棧上。

4.在MRC下,block內部訪問外部變量,同時對該block做一次copy操作,這個block是堆block__NSMallocBlock__,存儲在內存中的堆(heap)上。

三.一個由編譯的程序占用的內存分為以下幾個部分

1.棧區(stack):由編譯器自動分配釋放 ,存放函數的參數值,局部變量的值等。其 操作方式類似于數據結構中的棧。

2.堆區(heap):一般由程序員分配釋放, 若程序員不釋放,程序結束時可能由OS回收 。注意它與數據結構中的堆是兩回事,分配方式倒是類似于鏈表,呵呵。

3.全局區(靜態區)(static):全局變量和靜態變量的存儲是放在一塊的,初始化的 全局變量和靜態變量在一塊區域, 未初始化的全局變量和未初始化的靜態變量在相鄰的另 一塊區域。 - 程序結束后由系統釋放。

4.文字常量區:常量字符串就是放在這里的。 程序結束后由系統釋放

5.程序代碼區:存放函數體的二進制代碼。

四.block內部修改參數的注意事項

1.使用全局變量
全局變量所占用的內存只有一份,供所有函數共同調用,在Block定義時并未將全局變量的值或者指針傳給Block變量所指向的結構體,因此在調用Block之前對局部變量進行修改會影響Block內部的值,同時內部的值也是可以修改的。

2.使用局部變量
局部變量是存儲在靜態數據存儲區域的,也就是和程序擁有一樣的生命周期,也就是說在程序運行時,都能夠保證block訪問到一個有效的變量。但是其作用范圍還是局限于定義它的函數中,所以只能在block通過靜態局部變量的地址來進行訪問。

@interface ViewController () {
    NSInteger globalCountNum;
}

- (void)viewDidLoad {
    [super viewDidLoad];
    globalCountNum = 12;
    __block int localCountNum = 120;
    self.SayHelloTwo = ^(BOOL isCan) {
        globalCountNum = 10;
        localCountNum = 100;
        NSLog(@"globalCountNum_1 = %ld",(long)globalCountNum);
        NSLog(@"localCountNum_1 = %ld",(long)localCountNum);
    };
    NSLog(@"globalCountNum_2 = %ld",(long)globalCountNum);
    NSLog(@"localCountNum_2 = %ld",(long)localCountNum);
    self.SayHelloTwo(YES);
    NSLog(@"globalCountNum_3 = %ld",(long)globalCountNum);
    NSLog(@"localCountNum_3 = %ld",(long)localCountNum);
}

輸出結果:

2017-09-06 16:41:40.815 testGCD[1646:2899360] globalCountNum_2 = 12
2017-09-06 16:41:40.815 testGCD[1646:2899360] localCountNum_2 = 120
2017-09-06 16:41:40.816 testGCD[1646:2899360] globalCountNum_1 = 10
2017-09-06 16:41:40.816 testGCD[1646:2899360] localCountNum_1 = 100
2017-09-06 16:41:40.816 testGCD[1646:2899360] globalCountNum_3 = 10
2017-09-06 16:41:40.816 testGCD[1646:2899360] localCountNum_3 = 100
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容