1. 程式人生 > >iOS之block基礎及傳值

iOS之block基礎及傳值

最近碰到不少關於block的相關問題,在此做一些總結。

1.基本形式

返回值型別(^block)(形參列表)= ^(形參列表列表){程式碼段;};
eg: int(^block)(int,int) = ^(int i, int j){return i + j;};

定義沒有引數的三種寫法:
當沒有形參時,左邊形參列表括號必須寫,右邊可寫可不寫,左邊形參型別可寫可不寫;
void(^block)() = ^(){};
void(^ block)() = ^{};
void(^ block)(void) = ^{};

typedef定義Block型別

typedef int (^Block)(int, int);
//加上typedef之後,Block不再是一個變數,而是一個數據型別
Block b1, b2;
//使用typedef宣告的變數型別定義另個變數

2.塊物件作形參和塊物件作函式返回值

void fun(int (^b)(int x, int y))  
{  
    NSLog(@"b(3, 4) = %d", b(3, 4)); //在fun函式內部呼叫程式碼塊,並傳參。  
}

int main()  
{  
    //1,直接在實參位置定義block程式碼塊,這時候 如下的 int 表示程式碼塊的返回值型別,可以寫可以不寫,不寫的時候,程式會根據形參的返回值型別做型別轉換,一般情況這裡還是寫返回值型別為好,避免不必要的錯誤。  
    fun(^int(int x, int y) {  
        return x + y;  
    });  
    //2,先定義一個block程式碼塊,再將程式碼塊型別的變數作為實參傳給fun函式。  
int (^block)(int, int) = ^(int a, int b){ return a * b; }; fun(block);

3.塊物件中的變數行為

1)在block程式碼塊內部可以訪問定義的全域性變數,區域性變數,靜態區域性變數,但是訪問區域性靜態變數時候是隻讀的並且區域性變數和在程式碼塊中訪問到的不是同一個地址的變數,他們在數值上相等,互相似乎沒什麼聯絡。 因為程式碼塊中使用到區域性變數的時候,會將區域性變數進行const型別的copy,所以在程式碼塊中訪問到的區域性變數都是隻讀的;靜態變數和全域性變數都存放在靜態區,在程式執行過程中都存在,他們可以在不同的程式碼塊中共享,不同程式碼塊中訪問到的同一個全域性變數,區域性變數是同一塊記憶體的資料;對於普通區域性變數在程式碼塊中只讀,全域性變數和靜態區域性變數在程式碼塊中可以讀寫。
2)在塊句法的主體中,除塊句法內部的區域性變數和形參之外,還包含塊句法當前位置處可以訪問的變數;這些變數中包含外部變數也包含塊中可以訪問的區域性變數。
3)程式碼塊中訪問區域性變數時候,區域性變數會從棧記憶體被const型別的copy一份到堆記憶體中。
4)塊物件和函式指標的定義使用功能都差不多,塊物件的精髓之處就在於,在塊物件中可以訪問到上下文的變數,而函式指標不能

4,塊物件的例項和生命週期
1)塊句法也可以寫在函式的外部,當寫在函式外面時候,只是在靜態資料區分配一塊記憶體給塊物件,這塊區域在程式執行期間會一直存在。
2)塊句法寫在函式內部的時候,塊物件和變數的生命週期和普通區域性變數一樣,塊物件的記憶體區域會在執行包含塊物件的函式時儲存在棧上;該塊物件的生命週期就是函式執行期間。
3)在現實的實現中,當函式內的塊語法不包含自動變數的時候,就沒必要進行復制值,所以塊物件的記憶體區域也會被儲存在靜態資料區。
4)block程式碼塊被儲存在堆或者靜態區中,不會被儲存在棧中,如下圖可以說明這一點。

這裡寫圖片描述

5,塊物件的複製
函式內的塊物件和區域性變數的生命週期相同,都只是在函式的執行期間。但是在函式的方法呼叫引數中直接代入塊物件也是塊物件的一種非常常見的用法,這時候使用與函式呼叫關係或棧狀態無關的塊物件是非常必要的。
有一個函式可以複製塊物件到新的堆記憶體,通過使用該函式,即使是在函式內部定義的塊物件也能獨立於棧被持續的使用,此外還有一個函式可以釋放不需要的塊物件。
Block_copy( block )
引數為棧上的塊物件的時候,返回堆上的塊物件。引數為堆上的塊物件或者靜態區的塊物件,不進行復制,直接返回原物件,但是會增加引數塊物件的引用計數。
Block_release( block )
減少引數塊物件的引用計數。當引用計數減到0時候,塊物件被釋放。
Eg:
a = Block_copy(block);
Block_rlease(a);

6.指定特殊變數 __block
ARC環境下
這裡寫圖片描述
非ARC環境下
這裡寫圖片描述

7.Block傳值示例及注意事項

detailView頁面是第二層頁面,此處是從下級往上級傳值

DetailViewController.h
typedef void (^BLOCK)(NSString * string) ;//block的宣告
@property (copy ,nonatomic)BLOCK  block;

DetailViewController.m
-(void)viewDidDisappear
{
self.block(self.textField.text);//傳值
}

SecondViewController.m
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
DetailViewController * detailVC = (DetailViewController*)segue.destinationViewController;

//block賦值
__block SecondViewController * secondVC = self;//防止迴圈使用
detailVC.block = ^void(NSString * string){
secondVC.navigationItem.title = string;
};//注意分號
}

1.block沒有層級限制,可以從下往上,也可從上級往下級傳
2.block不容易找到實現方法的地方
3.宣告block屬性時用copy修飾