天天看點

iOS 中block結構的簡單用法(一)

自從block出現之後,很多API都開始采用這樣的結構,由此可見,block确實有許多優勢存在,這裡将一些簡單用法總結如下:

一、如何聲明一個block變量

我們通過^符号來聲明block類型,形式如下:

void (^myBlock)();

其中第一個void是傳回值,可以是任意類型,中間括号中^後面的是這個block變量的名字,我把它命名為myBlock,最後一個括号中是參數,如果多參數,可以寫成如下樣式:

int (^myBlock)(int,int);

同樣,你也可以給參數起名字:

int (^myBlock)(int a,int b);

很多時候,我們需要将我們聲明的block類型作為函數的參數,也有兩種方式:

1、-(void)func:(int (^)(int a,int b))block;

第二種方式是通過typedef定義一種新的類型,這也是大多數情況下采用的方式:

2、typedef int (^myBlock)(int a,int b) ;

-(void)func:(myBlock)block ;

二、如何實作一個block

既然block可以被聲明為變量,那麼就一定可以實作它,就像其他類型變量的指派。我自己對block的了解為它是一斷代碼塊,是以給它指派賦便是一段代碼段:

typedef int (^myBlock)(int,int) ;

@interface ViewController ()

{

   myBlock block1;

}

@end

@implementation ViewController

- (void)viewDidLoad {

   [super viewDidLoad];

   // Do any additional setup after loading the view, typically from a nib.

   block1 =^(int a, int b){

       return a+b;

   };

  NSLog(@"%d",block1(1,1));

這裡列印的結果是2,從這裡可以發現block和函數的功能很像。

注意:1、在上面的代碼裡 block1是一個對象,如果直接列印将列印對象位址

       2、block(),加上後面的括号才是執行block語句塊

三、block中通路對象的微妙關系

1、如果你在一個block塊中僅僅通路對象,而不是對他進行修改操作,是沒有任何問題的:

   int tem=2;

   block1 = ^(int a,int b){

       int count= tem+1;

       return count;

   NSLog(@"%d",block1(1,1));

而如果我在block塊中直接修改,編譯器會報錯:

 block1 = ^(int a,int b){

       tem+=1;

       return tem+1;

為什麼會出現這樣的情況,根據猜測,可能是block内部将通路的變量都備份了一份,如果我們在内部修改,外部的變量并不會被修改,我們可以通過列印變量的位址來證明這一點:

   [super viewDidLoad];

   NSLog(@"%p",&tem);

       NSLog(@"%p",&tem);

   NSLog(@"%d",block1(1,1));

列印結果如下:

iOS 中block結構的簡單用法(一)

可以看出,變量的位址已經改變。

2、__block 做了什麼

為了可以在block塊中通路并修改外部變量,我們常會把變量聲明成__block類型,通過上面的原理,可以發現,其實這個關鍵字隻做了一件事,如果在block中通路沒有添加這個關鍵字的變量,會通路到block自己拷貝的那一份變量,它是在block建立的時候建立的,而通路加了這個關鍵字的變量,則會通路這個變量的位址所對應的變量。我們可以通過代碼來證明:

   block1 = ^(int a,int b){  

       return tem+a+b;

   tem=4;

    __block int tem2=2;

   tem2=4;

    NSLog(@"%d",block1(1,1));

結果:

iOS 中block結構的簡單用法(一)

繼續閱讀