塊對象可以包含其訪問的自動變量的副本,但是這個變量是隻讀變量,當想要在多個塊對象之間共享變量,有三種方法:
(1)外部變量;
(2)靜態變量(static)
(3)若是在函數內部需要共享變量,需要將變量用__block修飾
注意:__block變量不能和static、auto、register同時指定。
下面舉例:
//
// test.c
// testClassCluster
//
// Created by DH on 2016/11/16.
// Copyright © 2016年 DH. All rights reserved.
//
#include "test.h"
#include <stdio.h>
#include <Block.h>
void (^g)(void) = NULL; //外部變量
int turn = 0;
void function(int n)
{
__block int testBlock = 0; // 函數內部的快之間共享變量
void (^b1)(void) = ^{ // 塊b1
testBlock += 1;
printf("%d:b1,n=%d,testBlock=%d\n",++turn,n,testBlock);
};
void (^b2)(void) = ^{ // 塊b2
testBlock += 20;
printf("%d:b2,n=%d,testBlock=%d\n",++turn,n,testBlock);
};
b1();
b2();
g = Block_copy(b1);
testBlock += n * 1000;
n = 999;
b2();
}
int main(void)
{
void (^myBlock)(void);
function(1);
myBlock = g;
myBlock();
function(2);
myBlock();
Block_release(g);
Block_release(myBlock);
return 0;
}
運行結果如下:
下面進行說明:
我們從主函數開始看,void (^myBlock)(void)是聲明一個塊對象使用的變量,接着function(1)調用函數,傳入參數n=1。來到function函數,執行b1(),調用塊b1:
void (^b1)(void) = ^{ // 塊b1
testBlock += 1;
printf("%d:b1,n=%d,testBlock=%d\n",++turn,n,testBlock);
};
testBlock += 1後,testBlock的值爲1,n的值爲傳入的1,++turn是先加1,所以爲1,因此
第一行結果是1:b1,n=1,testBlock=1;
同理,執行b2(),調用:
void (^b2)(void) = ^{ // 塊b2
testBlock += 20;
printf("%d:b2,n=%d,testBlock=%d\n",++turn,n,testBlock);
};
首選執行testBlock += 20。由於我們利用了__block對testBlock進行了修飾,所以b2可以共享testBlock.
因此,執行完這句後,testBlock的值變爲21。n依然是1,所以輸出爲2:b2,n=1,testBlock=21
接下來執行g = Block_copy(b1);
要理解這一句,首先要理解塊對象的複製,在函數內的塊對象的聲明週期和函數內聲明的變量一樣,當函數調用完畢就銷燬,同時這種塊對象的內存分配在棧上。如果我們不使用Block_copy()這個函數,直接g=b1,在函數function(1)執行完畢時,棧上的內存被回收,b1也就不存在了,而g還指向b1原來所在的內存,如有其它函數使用了這個內存,會造成難以預測的結果。而使用g = Block_copy(b1)則將b1複製到堆上面,從而解決了以上問題。
另外需要注意的是,這個時候調用塊複製函數,也會將這個時候塊中變量的值進行保存。而這個值是函數function(1)執行完畢後的值。
最後再執行函數最後一句b2(),得到結果3:b2,n=1,testBlock=1041,那麼第一次函數調用結束,這時要將最後的testBlock的值保存到堆上面。
接着回到主函數的調用:
myBlock = g;
myBlock();
輸出:
4:b1,n=1,testBlock=1042
後面的執行不再贅述,來到最後一句:myBlock();
它輸出的結果是:8:b1,n=1,testBlock=1043,
我們發現在第一次調用的時候的變調testBlock的值一直被保留下來了。