《Objective-C高級編程》 學(xué)習(xí)筆記 Block

由《Objective-C高級編程》第二章入手:
1.block是C語言的一項重要的特性,block到底是什么?
簡而言之奶稠,block是帶有自動變量的匿名函數(shù),匿名函數(shù):即不帶名稱的函數(shù)

補一下c語言的一些:

//聲明 調(diào)用函數(shù)
int func(int count);
int result = func(10);

下面這個使用函數(shù)指針來代替調(diào)用函數(shù),似乎不用知道函數(shù)名也能直接使用該函數(shù)

int result = (*funcptr)(10);

但實際上 如果不使用想賦值的函數(shù)的名稱谜诫,就無法取得該函數(shù)的地址

int (*funcptr)(int) = &func;
int result = (*funcptr)(10);

而通過block可以使用不帶名稱的函數(shù),能夠編寫不帶名稱的函數(shù)對程序員來說相當(dāng)具有吸引力涮阔。

2.Block語法與Block類型變量猜绣,可以理解“帶有自動變量值的匿名函數(shù)”中“匿名函數(shù)”。而“帶有自動變量值”在Blocks中表現(xiàn)為“截獲自動變量值”敬特。而自動變量(局部變量)的特點:

  • 函數(shù)內(nèi)部聲明
  • 僅當(dāng)函數(shù)執(zhí)行時存在
  • 僅在本文件本函數(shù)內(nèi)可訪問
  • 存儲位置:自動保存在函數(shù)的每次執(zhí)行的【棧幀】中掰邢,并隨著函數(shù)結(jié)束后自動釋放,另外伟阔,函數(shù)每次執(zhí)行則保存在【椑敝】中
- (float)caculateResult{
 float a = 1.0;
 float b = 2.0;
 return a + b;
}

3.block與函數(shù)的區(qū)別:
block是封裝了一段代碼的OC對象,可以被設(shè)為Property, 在調(diào)用block的地方block都會被替換成相應(yīng)的代碼皱炉,相當(dāng)于內(nèi)聯(lián)函數(shù)怀估。

函數(shù)可以使代碼更加整潔易讀,使用block會使代碼可讀性變差合搅,另外函數(shù)可以做單元測試多搀,block無法做單元測試。

4.block語法

block可以認為是匿名的C函數(shù)灾部,它的語法格式是這樣的:

^ (int i){
  return 0;
}

實際上康铭,該block語法使用率省略方式,其完整形式如下:

^ void(int i){
  return 0;
}

如上赌髓,所以與C語言函數(shù)相比 有兩點不同:
1.沒有函數(shù)名
2.帶有 ^
即bloc格式為: ^ 返回值類型 (參數(shù)列表) { C語言中允許使用的表達式 }
還有一種省略返回值類型的格式:
^ 參數(shù)列表 表達式

^ (int count) {
return count + 1;
}

不使用參數(shù)時 參數(shù)列表也可以省略:

^ void (void) {
printf("blocks\n");
}

可省略為:

^ {
printf("blocks\n");
}

5.源代碼中一旦使用了block語法就相當(dāng)于生成了可賦值給block類型變量的值
block既指源代碼中的block語法从藤,也指由block語法所生成的值

下面是用語法將block值賦值給block類型變量

int (^blk)(int) = ^(int count) {
return count + 1;
}

在函數(shù)返回值中指定block類型 可以將block作為函數(shù)的返回值返回

int (^func())(int)
{
return ^(int count){ return (count+1) };
}

C中 在函數(shù)參數(shù)中使用block類型變量并在函數(shù)中執(zhí)行block的例子如下:

int func(blk_t blk, int rate) 
{
return blk(rate);
}

OC中:

(int) methodBlock:(blk_t)blk rate:(int)rate
{
return blk(rate);
}

typedef聲明block類型變量的格式:

typedef 返回值類型 (^塊名) (參數(shù)列表)

6.block作用: 截獲自動變量值:
block表達式可以截獲所使用的自動(局部)變量的值,即保存該自動變量的瞬間值锁蠕,即使block的調(diào)用語句在該值修改之后被調(diào)用夷野,但是實現(xiàn)部分在該值修改之前即可。

typedef void (^block_t)();
int main () 
{
    int a = 0;
    int b = 1;
    block_t blk = ^ () {
        printf("block: %d", a);
    }
    a = 2;
    blk();
    return 0;
}

7.block中如果給截獲的自動變量賦值 就會產(chǎn)生編譯錯誤荣倾。
但是調(diào)用變更該截獲的obje-C對象的方法不會產(chǎn)生編譯錯誤:

id array = [[NSMutalbeArray alloc] init];
void (^blk)(void) = ^ {
id obj = [[NSObject alloc] init];
[array addObject:obj];
};

8.block中截獲自動變量的方法并沒有實現(xiàn)對C語言數(shù)組的截獲悯搔,這樣打印C語言數(shù)組會出現(xiàn)編譯錯誤,
但是使用數(shù)組指針可以解決該問題

9.總的來說舌仍,截獲自動變量值意味著在執(zhí)行block語法時鳖孤,block語法表達式所使用的自動變量值被保存到block的結(jié)構(gòu)體實例(即block自身)中

10.block類共有三種:

  • _NSConcreteStackBlock

儲存在程序區(qū)域的數(shù)據(jù)區(qū)域

  • _NSConcreteGlobalBlock

儲存在程序區(qū)域的堆區(qū)

  • _NSConcreteMallocBlock

儲存在程序區(qū)域的棧區(qū)

11.即使在函數(shù)內(nèi)而不再記述廣域變量的地方使用Block語法時,只要Block不截獲自動變量抡笼,就是block里面的代碼與自動(局部)變量無關(guān),就可以將Block用結(jié)構(gòu)體實例設(shè)置在程序的數(shù)據(jù)區(qū)域

typedef int (^blk_t)(int);
for (int rate = 0; rate < 10; rate++) {
blk_t blk = ^(int count) {
return count;
}
}

總結(jié)就是:
在下面這些情況黄鳍,Block為_NSConcreteGlobalBlock類對象推姻,即配置在程序的數(shù)據(jù)區(qū)域中

  • 記述全局變量的地方有Block語法時
  • Block語法的表達式中不使用應(yīng)截獲的自動變量時
    除此之外的Block語法生成的Block為_NSConcreteStackBlock類對象,且設(shè)置在棧上

12.配置在全局變量上的Block,從變量作用域外也可以通過指針安全的使用框沟,但是
設(shè)置在棧上的Block藏古,如果其所屬變量的作用域結(jié)束增炭,該Block就會被廢棄。
解決方法:
將Block和_block變量從棧上復(fù)制到堆上的方法來解決
復(fù)制到堆上的Block將_NSConcreteMallocBlock類對象寫入Block用結(jié)構(gòu)體實例的成員變量isa

imp1,isa = &__NSConcreteMallocBlock;

13.什么時候棧上的Block復(fù)制到堆拧晕?

  • 調(diào)用Block的copy實例方法時
  • Block作為函數(shù)返回值返回時
  • 將Block賦值給附有_strong修飾符id類型的類或Block類型成員變量時
  • 在方法中含有usingBlock的Cocoa框架方法或GCD的API中傳遞Block時

14.在不調(diào)用copy函數(shù)的情況下隙姿,即使截獲了對象,它也會隨著變量作用域的結(jié)束而廢棄(P125)
因此厂捞,Block中使用對象類型自動變量時输玷,除以下情形外,推薦調(diào)用Block的copy實例方法:

  • Block作為函數(shù)返回值返回時
  • 將Block賦值給類的附有__strong修飾符的id類型或Block類型成員變量時
  • 向方法名中含有usingBlock的Cocoa框架方法或GCD的API中傳遞Block時

15.即使對象賦值復(fù)制到堆上的附有__strong修飾符的對象類型__block變量中靡馁,只要__block變量在堆上繼續(xù)存在欲鹏,那么該對象就會繼續(xù)處于被持有的狀態(tài)。這與Block中使用賦值給附有__strong修飾符的對象類型自動變量的對象相同

16.這段代碼的執(zhí)行結(jié)果是臭墨?

blk_t blk;
{
id array = [[NSMutableArray alloc] init];
id __weak array2 = array;

blk = [^(id obj) {
[array2 addObject:obj];
NSLog(@"array2 count = %ld", [array2 count]);
} copy];
}

blk([[NSObject alloc] init]);
blk([[NSObject alloc] init]);
blk([[NSObject alloc] init]);

該源代碼執(zhí)行結(jié)果為:

array2 count = 0;
array2 count = 0;
array2 count = 0;

原因:

  • 由于附有__strong修飾符的變量array在該變量作用域結(jié)束的同時被釋放赔嚎,廢棄,nil被賦值在附有__weak修飾符的變量array2中胧弛,該代碼可正常執(zhí)行

17.看一段這個代碼:

- (id)init {
self = [super init];

blk_ = ^{
NSLog(@"obj_ = %@", obj_);
}
return self;
}

會造成編譯錯誤尤误。
因為Block語法內(nèi)使用的obj_實際上截獲了self.對編譯器來說,obj_只不過是對象用結(jié)構(gòu)體的成員變量

blk_ = ^{
NSLog("obj_ = %@", self->obj_);
}

18.只要Block有一次復(fù)制并配置在堆上结缚,就可通過retain實例方法持有
但對于配置在棧上的Block調(diào)用retain實例方法則不起任何作用

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末损晤,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子掺冠,更是在濱河造成了極大的恐慌沉馆,老刑警劉巖,帶你破解...
    沈念sama閱讀 212,383評論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件德崭,死亡現(xiàn)場離奇詭異斥黑,居然都是意外死亡,警方通過查閱死者的電腦和手機眉厨,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,522評論 3 385
  • 文/潘曉璐 我一進店門锌奴,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人憾股,你說我怎么就攤上這事鹿蜀。” “怎么了服球?”我有些...
    開封第一講書人閱讀 157,852評論 0 348
  • 文/不壞的土叔 我叫張陵茴恰,是天一觀的道長。 經(jīng)常有香客問我斩熊,道長往枣,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,621評論 1 284
  • 正文 為了忘掉前任,我火速辦了婚禮分冈,結(jié)果婚禮上圾另,老公的妹妹穿的比我還像新娘。我一直安慰自己雕沉,他們只是感情好集乔,可當(dāng)我...
    茶點故事閱讀 65,741評論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著坡椒,像睡著了一般扰路。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上肠牲,一...
    開封第一講書人閱讀 49,929評論 1 290
  • 那天幼衰,我揣著相機與錄音,去河邊找鬼缀雳。 笑死渡嚣,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的肥印。 我是一名探鬼主播识椰,決...
    沈念sama閱讀 39,076評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼深碱!你這毒婦竟也來了腹鹉?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,803評論 0 268
  • 序言:老撾萬榮一對情侶失蹤敷硅,失蹤者是張志新(化名)和其女友劉穎功咒,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體绞蹦,經(jīng)...
    沈念sama閱讀 44,265評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡力奋,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,582評論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了幽七。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片景殷。...
    茶點故事閱讀 38,716評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖澡屡,靈堂內(nèi)的尸體忽然破棺而出猿挚,到底是詐尸還是另有隱情,我是刑警寧澤驶鹉,帶...
    沈念sama閱讀 34,395評論 4 333
  • 正文 年R本政府宣布绩蜻,位于F島的核電站,受9級特大地震影響室埋,放射性物質(zhì)發(fā)生泄漏辜羊。R本人自食惡果不足惜踏兜,卻給世界環(huán)境...
    茶點故事閱讀 40,039評論 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望八秃。 院中可真熱鬧,春花似錦肉盹、人聲如沸昔驱。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,798評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽骤肛。三九已至,卻和暖如春窍蓝,著一層夾襖步出監(jiān)牢的瞬間腋颠,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,027評論 1 266
  • 我被黑心中介騙來泰國打工吓笙, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留淑玫,地道東北人。 一個月前我還...
    沈念sama閱讀 46,488評論 2 361
  • 正文 我出身青樓面睛,卻偏偏與公主長得像絮蒿,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子叁鉴,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,612評論 2 350

推薦閱讀更多精彩內(nèi)容