iOS 開發(fā):『Blocks』詳盡總結(jié) (一)基本使用

推薦閱讀:iOS開發(fā)——BAT面試題合集(持續(xù)更新中)

本文用來(lái)介紹 iOS開發(fā)中 『Blocks』的基本使用焰轻。通過(guò)本文您將了解到:

  1. 什么是 Blocks
  2. Blocks 變量語(yǔ)法
  3. Blocks 變量的聲明與賦值
  4. Blocks 變量截獲局部變量值特性
  5. 使用 __block 說(shuō)明符
  6. Blocks 變量的循環(huán)引用以及如何避免

文中 Demo 我已放在了 Github 上,Demo 鏈接:傳送門

1. 什么是 Blocks 翰铡?

一句話總結(jié):Blocks 是帶有 局部變量匿名函數(shù)(不帶名稱的函數(shù))崎逃。

Blocks 也被稱作 閉包蔓涧、代碼塊耸峭。展開來(lái)講隘谣,Blocks 就是一個(gè)代碼塊瞒斩,把你想要執(zhí)行的代碼封裝在這個(gè)代碼塊里破婆,等到需要的時(shí)候再去調(diào)用。

下邊我們先來(lái)理解 局部變量胸囱、匿名函數(shù) 的含義祷舀。

1.1 局部變量

在 C 語(yǔ)言中,定義在函數(shù)內(nèi)部的變量稱為 局部變量烹笔。它的作用域僅限于函數(shù)內(nèi)部裳扯, 離開該函數(shù)后就是無(wú)效的,再使用就會(huì)報(bào)錯(cuò)谤职。

|

<pre style="font-family: consolas, Menlo, "PingFang SC", "Microsoft YaHei", monospace; font-size: 13px; overflow: auto; margin: 0px; padding: 10px; color: rgb(102, 102, 102); background: rgb(41, 41, 41); line-height: 1.6; border: none; text-align: right;">1
2
3
4
5
6
7
8
9
10
11
</pre>

|

<pre style="font-family: consolas, Menlo, "PingFang SC", "Microsoft YaHei", monospace; font-size: 13px; overflow: auto; margin: 0px; padding: 10px; color: rgb(234, 234, 234); background: rgb(0, 0, 0); line-height: 1.6; border: none; width: 251px;">int x, y; // x饰豺,y 為全局變量

int fun(int a) {
int b, c; //a,b允蜈,c 為局部變量
return a+b+c;
}

int main() {
int m, n; // m冤吨,n 為局部變量
return 0;
}
</pre>

|

從上邊的代碼中,我們可以看出:

  1. 我們?cè)陂_始位置定義了變量 x 和 變量 y饶套。 x 和 y 都是全局變量漩蟆。它們的作用域默認(rèn)是整個(gè)程序,也就是所有的源文件妓蛮,包括 .c 和 .h 文件爆安。
  2. 而我們?cè)?fun() 函數(shù)中定義了變量 a、變量 b仔引、變量 c扔仓。它們的作用域是 fun() 函數(shù)。只能在 fun() 函數(shù)內(nèi)部使用咖耘,離開 fun() 函數(shù)就是無(wú)效的翘簇。
  3. 同理,main() 函數(shù)中的變量 m儿倒、變量 n 也只能在 main() 函數(shù)內(nèi)部使用版保。

1.2 匿名函數(shù)

匿名函數(shù)指的是不帶有名稱的函數(shù)。但是 C 語(yǔ)言中不允許存在這樣的函數(shù)夫否。

在 C 語(yǔ)言中彻犁,一個(gè)普通的函數(shù)長(zhǎng)這樣子:

|

<pre style="font-family: consolas, Menlo, "PingFang SC", "Microsoft YaHei", monospace; font-size: 13px; overflow: auto; margin: 0px; padding: 10px; color: rgb(102, 102, 102); background: rgb(41, 41, 41); line-height: 1.6; border: none; text-align: right;">1
</pre>

|

<pre style="font-family: consolas, Menlo, "PingFang SC", "Microsoft YaHei", monospace; font-size: 13px; overflow: auto; margin: 0px; padding: 10px; color: rgb(234, 234, 234); background: rgb(0, 0, 0); line-height: 1.6; border: none; width: 125px;">int fun(int a);
</pre>

|

fun 就是這個(gè)函數(shù)的名稱,在調(diào)用的時(shí)候必須要使用該函數(shù)的名稱 fun 來(lái)調(diào)用凰慈。

|

<pre style="font-family: consolas, Menlo, "PingFang SC", "Microsoft YaHei", monospace; font-size: 13px; overflow: auto; margin: 0px; padding: 10px; color: rgb(102, 102, 102); background: rgb(41, 41, 41); line-height: 1.6; border: none; text-align: right;">1
</pre>

|

<pre style="font-family: consolas, Menlo, "PingFang SC", "Microsoft YaHei", monospace; font-size: 13px; overflow: auto; margin: 0px; padding: 10px; color: rgb(234, 234, 234); background: rgb(0, 0, 0); line-height: 1.6; border: none; width: 167px;">int result = fun(10);
</pre>

|

在 C 語(yǔ)言中汞幢,我們還可以通過(guò)函數(shù)指針來(lái)直接調(diào)用函數(shù)。但是在給函數(shù)指針賦值的時(shí)候微谓,同樣也是需要知道函數(shù)的名稱森篷。

|

<pre style="font-family: consolas, Menlo, "PingFang SC", "Microsoft YaHei", monospace; font-size: 13px; overflow: auto; margin: 0px; padding: 10px; color: rgb(102, 102, 102); background: rgb(41, 41, 41); line-height: 1.6; border: none; text-align: right;">1
2
</pre>

|

<pre style="font-family: consolas, Menlo, "PingFang SC", "Microsoft YaHei", monospace; font-size: 13px; overflow: auto; margin: 0px; padding: 10px; color: rgb(234, 234, 234); background: rgb(0, 0, 0); line-height: 1.6; border: none; width: 209px;">int (funPtr)(int) = &fun;
int result = (
funPtr)(10);
</pre>

|

而我們通過(guò) Blocks,可以直接使用函數(shù)豺型,不用給函數(shù)命名仲智。


2. Blocks 變量語(yǔ)法

我們使用 ^ 運(yùn)算符來(lái)聲明 Blocks 變量,并將 Blocks 對(duì)象主體部分包含在 {} 中姻氨,同時(shí)钓辆,句尾加 ; 表示結(jié)尾。

下邊來(lái)看一個(gè)官方的示例:

|

<pre style="font-family: consolas, Menlo, "PingFang SC", "Microsoft YaHei", monospace; font-size: 13px; overflow: auto; margin: 0px; padding: 10px; color: rgb(102, 102, 102); background: rgb(41, 41, 41); line-height: 1.6; border: none; text-align: right;">1
2
3
4
</pre>

|

<pre style="font-family: consolas, Menlo, "PingFang SC", "Microsoft YaHei", monospace; font-size: 13px; overflow: auto; margin: 0px; padding: 10px; color: rgb(234, 234, 234); background: rgb(0, 0, 0); line-height: 1.6; border: none; width: 258px;">int multiplier = 7;
int (^ myBlock)(int)= ^(int num) {
return num * multiplier;
};
</pre>

|

這個(gè) Blocks 示例中肴焊,myBlock 是聲明的塊對(duì)象前联,返回類型是 整型值,myBlock 塊對(duì)象有一個(gè) 參數(shù)抖韩,參數(shù)類型為整型值蛀恩,參數(shù)名稱為 num。myBlock 塊對(duì)象的 主體部分return num * multiplier;茂浮,包含在 {} 中双谆。

參考上面的示例,我們可以將 Blocks 表達(dá)式語(yǔ)法表述為:

^ 返回值類型 (參數(shù)列表) { 表達(dá)式 };

例如席揽,我們可以寫出這樣的 Block 語(yǔ)法:

|

<pre style="font-family: consolas, Menlo, "PingFang SC", "Microsoft YaHei", monospace; font-size: 13px; overflow: auto; margin: 0px; padding: 10px; color: rgb(102, 102, 102); background: rgb(41, 41, 41); line-height: 1.6; border: none; text-align: right;">1
</pre>

|

<pre style="font-family: consolas, Menlo, "PingFang SC", "Microsoft YaHei", monospace; font-size: 13px; overflow: auto; margin: 0px; padding: 10px; color: rgb(234, 234, 234); background: rgb(0, 0, 0); line-height: 1.6; border: none; width: 300px;">^ int (int count) { return count + 1; };
</pre>

|

Blocks 規(guī)定可以省略好多項(xiàng)目顽馋。例如:返回值類型參數(shù)列表幌羞。如果用不到寸谜,都可以省略。

2.1 省略返回值類型:^ (參數(shù)列表) { 表達(dá)式 };

上邊的 Blocks 語(yǔ)法就可以寫為:

|

<pre style="font-family: consolas, Menlo, "PingFang SC", "Microsoft YaHei", monospace; font-size: 13px; overflow: auto; margin: 0px; padding: 10px; color: rgb(102, 102, 102); background: rgb(41, 41, 41); line-height: 1.6; border: none; text-align: right;">1
</pre>

|

<pre style="font-family: consolas, Menlo, "PingFang SC", "Microsoft YaHei", monospace; font-size: 13px; overflow: auto; margin: 0px; padding: 10px; color: rgb(234, 234, 234); background: rgb(0, 0, 0); line-height: 1.6; border: none; width: 272px;">^ (int count) { return count + 1; };
</pre>

|

表達(dá)式中属桦,return 語(yǔ)句使用的是 count + 1 語(yǔ)句的返回類型熊痴。如果表達(dá)式中有多個(gè) return 語(yǔ)句他爸,則所有 return 語(yǔ)句的返回值類型必須一致。

如果表達(dá)式中沒(méi)有 return 語(yǔ)句果善,則可以用 void 表示诊笤,或者也省略不寫。代碼如下:巾陕。

|

<pre style="font-family: consolas, Menlo, "PingFang SC", "Microsoft YaHei", monospace; font-size: 13px; overflow: auto; margin: 0px; padding: 10px; color: rgb(102, 102, 102); background: rgb(41, 41, 41); line-height: 1.6; border: none; text-align: right;">1
2
</pre>

|

<pre style="font-family: consolas, Menlo, "PingFang SC", "Microsoft YaHei", monospace; font-size: 13px; overflow: auto; margin: 0px; padding: 10px; color: rgb(234, 234, 234); background: rgb(0, 0, 0); line-height: 1.6; border: none; width: 524px;">^ void (int count) { printf("%d\n", count); }; // 返回值類型使用 void
^ (int count) { printf("%d\n", count); }; // 省略返回值類型
</pre>

|

2.2 省略參數(shù)列表 ^ 返回值類型 (void) { 表達(dá)式 };

如果表達(dá)式中讨跟,沒(méi)有使用參數(shù),則用 void 表示鄙煤,也可以省略 void晾匠。

|

<pre style="font-family: consolas, Menlo, "PingFang SC", "Microsoft YaHei", monospace; font-size: 13px; overflow: auto; margin: 0px; padding: 10px; color: rgb(102, 102, 102); background: rgb(41, 41, 41); line-height: 1.6; border: none; text-align: right;">1
2
</pre>

|

<pre style="font-family: consolas, Menlo, "PingFang SC", "Microsoft YaHei", monospace; font-size: 13px; overflow: auto; margin: 0px; padding: 10px; color: rgb(234, 234, 234); background: rgb(0, 0, 0); line-height: 1.6; border: none; width: 371px;">^ int (void) { return 1; }; // 參數(shù)列表使用 void
^ int { return 1; }; // 省略參數(shù)列表類型
</pre>

|

2.3 省略返回值類型、參數(shù)列表:^ { 表達(dá)式 };

從上邊 2.1 中可以看出梯刚,無(wú)論有無(wú)返回值凉馆,都可以省略返回值類型。并且乾巧,從 2.2 中可以看出句喜,如果不需要參數(shù)列表的話,也可以省略參數(shù)列表沟于。則代碼可以簡(jiǎn)化為:

|

<pre style="font-family: consolas, Menlo, "PingFang SC", "Microsoft YaHei", monospace; font-size: 13px; overflow: auto; margin: 0px; padding: 10px; color: rgb(102, 102, 102); background: rgb(41, 41, 41); line-height: 1.6; border: none; text-align: right;">1
</pre>

|

<pre style="font-family: consolas, Menlo, "PingFang SC", "Microsoft YaHei", monospace; font-size: 13px; overflow: auto; margin: 0px; padding: 10px; color: rgb(234, 234, 234); background: rgb(0, 0, 0); line-height: 1.6; border: none; width: 188px;">^ { printf("Blocks"); };
</pre>

|


3. Blocks 變量的聲明與賦值

3.1 Blocks 變量的聲明與賦值語(yǔ)法

Blocks 變量的聲明與賦值語(yǔ)法可以總結(jié)為:

返回值類型 (^變量名) (參數(shù)列表) = Blocks 表達(dá)式

注意:此處返回值類型不可以省略咳胃,若無(wú)返回值,則使用 void 作為返回值類型旷太。

例如展懈,定義一個(gè)變量名為 blk 的 Blocks 變量:

|

<pre style="font-family: consolas, Menlo, "PingFang SC", "Microsoft YaHei", monospace; font-size: 13px; overflow: auto; margin: 0px; padding: 10px; color: rgb(102, 102, 102); background: rgb(41, 41, 41); line-height: 1.6; border: none; text-align: right;">1
2
3
</pre>

|

<pre style="font-family: consolas, Menlo, "PingFang SC", "Microsoft YaHei", monospace; font-size: 13px; overflow: auto; margin: 0px; padding: 10px; color: rgb(234, 234, 234); background: rgb(0, 0, 0); line-height: 1.6; border: none; width: 410px;">int (^blk) (int) = ^(int count) { return count + 1; };
int (^blk1) (int); // 聲明變量名為 blk1 的 Blocks 變量
blk1 = blk; // 將 blk 賦值給 blk1
</pre>

|

Blocks 變量的聲明語(yǔ)法有點(diǎn)復(fù)雜,其實(shí)我們可以和 C 語(yǔ)言函數(shù)指針的聲明類比著來(lái)記供璧。

Blocks 變量的聲明就是把聲明函數(shù)指針類型的變量 * 變?yōu)?^存崖。

|

<pre style="font-family: consolas, Menlo, "PingFang SC", "Microsoft YaHei", monospace; font-size: 13px; overflow: auto; margin: 0px; padding: 10px; color: rgb(102, 102, 102); background: rgb(41, 41, 41); line-height: 1.6; border: none; text-align: right;">1
2
3
4
5
6
7
8
</pre>

|

<pre style="font-family: consolas, Menlo, "PingFang SC", "Microsoft YaHei", monospace; font-size: 13px; overflow: auto; margin: 0px; padding: 10px; color: rgb(234, 234, 234); background: rgb(0, 0, 0); line-height: 1.6; border: none; width: 405px;">// C 語(yǔ)言函數(shù)指針聲明與賦值
int func (int count) {
return count + 1;
}
int (*funcptr)(int) = &func;

// Blocks 變量聲明與賦值
int (^blk) (int) = ^(int count) { return count + 1; };
</pre>

|

3.2 Blocks 變量的聲明與賦值的使用

3.2.1 作為局部變量:返回值類型 (^變量名) (參數(shù)列表) = 返回值類型 (參數(shù)列表) { 表達(dá)式 };

我們可以把 Blocks 變量作為局部變量,在一定范圍內(nèi)(函數(shù)睡毒、方法內(nèi)部)使用来惧。

|

<pre style="font-family: consolas, Menlo, "PingFang SC", "Microsoft YaHei", monospace; font-size: 13px; overflow: auto; margin: 0px; padding: 10px; color: rgb(102, 102, 102); background: rgb(41, 41, 41); line-height: 1.6; border: none; text-align: right;">1
2
3
4
5
6
7
8
</pre>

|

<pre style="font-family: consolas, Menlo, "PingFang SC", "Microsoft YaHei", monospace; font-size: 13px; overflow: auto; margin: 0px; padding: 10px; color: rgb(234, 234, 234); background: rgb(0, 0, 0); line-height: 1.6; border: none; width: 314px;">// Blocks 變量作為本地變量

  • (void)useBlockAsLocalVariable {
    void (^myLocalBlock)(void) = ^{
    NSLog(@"useBlockAsLocalVariable");
    };

    myLocalBlock();
    }
    </pre>

|

3.2.2 作為帶有 property 聲明的成員變量:@property (nonatomic, copy) 返回值類型 (^變量名) (參數(shù)列表);

作用類似于 delegate,實(shí)現(xiàn) Blocks 回調(diào)演顾。

|

<pre style="font-family: consolas, Menlo, "PingFang SC", "Microsoft YaHei", monospace; font-size: 13px; overflow: auto; margin: 0px; padding: 10px; color: rgb(102, 102, 102); background: rgb(41, 41, 41); line-height: 1.6; border: none; text-align: right;">1
2
3
4
5
6
7
8
9
10
11
</pre>

|

<pre style="font-family: consolas, Menlo, "PingFang SC", "Microsoft YaHei", monospace; font-size: 13px; overflow: auto; margin: 0px; padding: 10px; color: rgb(234, 234, 234); background: rgb(0, 0, 0); line-height: 1.6; border: none; width: 433px;">/* Blocks 變量作為帶有 property 聲明的成員變量 */
@property (nonatomic, copy) void (^myPropertyBlock) (void);

// Blocks 變量作為帶有 property 聲明的成員變量

  • (void)useBlockAsProperty {
    self.myPropertyBlock = ^{
    NSLog(@"useBlockAsProperty");
    };

    self.myPropertyBlock();
    }
    </pre>

|

3.2.3 作為 OC 方法參數(shù):- (void)someMethodThatTaksesABlock:(返回值類型 (^)(參數(shù)列表)) 變量名;

可以把 Blocks 變量作為 OC 方法中的一個(gè)參數(shù)來(lái)使用供搀,通常 blocks 變量寫在方法名的最后。

|

<pre style="font-family: consolas, Menlo, "PingFang SC", "Microsoft YaHei", monospace; font-size: 13px; overflow: auto; margin: 0px; padding: 10px; color: rgb(102, 102, 102); background: rgb(41, 41, 41); line-height: 1.6; border: none; text-align: right;">1
2
3
4
</pre>

|

<pre style="font-family: consolas, Menlo, "PingFang SC", "Microsoft YaHei", monospace; font-size: 13px; overflow: auto; margin: 0px; padding: 10px; color: rgb(234, 234, 234); background: rgb(0, 0, 0); line-height: 1.6; border: none; width: 468px;">// Blocks 變量作為 OC 方法參數(shù)

  • (void)someMethodThatTakesABlock:(void (^)(NSString *)) block {
    block(@"someMethodThatTakesABlock:");
    }
    </pre>

|

3.2.4 調(diào)用含有 Block 參數(shù)的 OC方法:[someObject someMethodThatTakesABlock:^返回值類型 (參數(shù)列表) { 表達(dá)式}];

|

<pre style="font-family: consolas, Menlo, "PingFang SC", "Microsoft YaHei", monospace; font-size: 13px; overflow: auto; margin: 0px; padding: 10px; color: rgb(102, 102, 102); background: rgb(41, 41, 41); line-height: 1.6; border: none; text-align: right;">1
2
3
4
5
6
</pre>

|

<pre style="font-family: consolas, Menlo, "PingFang SC", "Microsoft YaHei", monospace; font-size: 13px; overflow: auto; margin: 0px; padding: 10px; color: rgb(234, 234, 234); background: rgb(0, 0, 0); line-height: 1.6; border: none; width: 398px;">// 調(diào)用含有 Block 參數(shù)的 OC方法

  • (void)useBlockAsMethodParameter {
    [self someMethodThatTakesABlock:^(NSString *str) {
    NSLog(@"%@",str);
    }];
    }
    </pre>

|

通過(guò) 3.2.3 和 3.2.4 中钠至,Blocks 變量作為 OC 方法參數(shù)的調(diào)用葛虐,我們同樣可以實(shí)現(xiàn)類似于 delegate 的作用,即 Blocks 回調(diào)(后邊應(yīng)用場(chǎng)景中會(huì)講)棉钧。

3.2.5 作為 typedef 聲明類型:

|

<pre style="font-family: consolas, Menlo, "PingFang SC", "Microsoft YaHei", monospace; font-size: 13px; overflow: auto; margin: 0px; padding: 10px; color: rgb(102, 102, 102); background: rgb(41, 41, 41); line-height: 1.6; border: none; text-align: right;">1
2
</pre>

|

<pre style="font-family: consolas, Menlo, "PingFang SC", "Microsoft YaHei", monospace; font-size: 13px; overflow: auto; margin: 0px; padding: 10px; color: rgb(234, 234, 234); background: rgb(0, 0, 0); line-height: 1.6; border: none; width: 358px;">typedef 返回值類型 (^聲明名稱)(參數(shù)列表);
聲明名稱 變量名 = ^返回值類型(參數(shù)列表) { 表達(dá)式 };
</pre>

|

|

<pre style="font-family: consolas, Menlo, "PingFang SC", "Microsoft YaHei", monospace; font-size: 13px; overflow: auto; margin: 0px; padding: 10px; color: rgb(102, 102, 102); background: rgb(41, 41, 41); line-height: 1.6; border: none; text-align: right;">1
2
3
4
5
6
7
8
9
10
11
</pre>

|

<pre style="font-family: consolas, Menlo, "PingFang SC", "Microsoft YaHei", monospace; font-size: 13px; overflow: auto; margin: 0px; padding: 10px; color: rgb(234, 234, 234); background: rgb(0, 0, 0); line-height: 1.6; border: none; width: 500px;">// Blocks 變量作為 typedef 聲明類型

  • (void)useBlockAsATypedef {
    typedef void (^TypeName)(void);

// 之后就可以使用 TypeName 來(lái)定義無(wú)返回類型屿脐、無(wú)參數(shù)列表的 block 了。
TypeName myTypedefBlock = ^{
NSLog(@"useBlockAsATypedef");
};

myTypedefBlock();

}
</pre>

|


4. Blocks 變量截獲局部變量值特性

先來(lái)看一個(gè)例子。

|

<pre style="font-family: consolas, Menlo, "PingFang SC", "Microsoft YaHei", monospace; font-size: 13px; overflow: auto; margin: 0px; padding: 10px; color: rgb(102, 102, 102); background: rgb(41, 41, 41); line-height: 1.6; border: none; text-align: right;">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
</pre>

|

<pre style="font-family: consolas, Menlo, "PingFang SC", "Microsoft YaHei", monospace; font-size: 13px; overflow: auto; margin: 0px; padding: 10px; color: rgb(234, 234, 234); background: rgb(0, 0, 0); line-height: 1.6; border: none; width: 365px;">// 使用 Blocks 截獲局部變量值

  • (void)useBlockInterceptLocalVariables {
    int a = 10, b = 20;

    void (^myLocalBlock)(void) = ^{
    printf("a = %d, b = %d\n",a, b);
    };

    myLocalBlock(); // 打印結(jié)果:a = 10, b = 20

    a = 20;
    b = 30;

    myLocalBlock(); // 打印結(jié)果:a = 10, b = 20
    }
    </pre>

|

為什么兩次打印結(jié)果都是 a = 10, b = 20的诵?

明明在第一次調(diào)用 myLocalBlock(); 之后已經(jīng)重新給變量 a万栅、變量 b 賦值了,為什么第二次調(diào)用 myLocalBlock(); 的時(shí)候奢驯,使用的還是之前對(duì)應(yīng)變量的值申钩?

因?yàn)?Block 語(yǔ)法的表達(dá)式使用的是它之前聲明的局部變量 a、變量 b瘪阁。Blocks 中,Block 表達(dá)式截獲所使用的局部變量的值邮偎,保存了該變量的瞬時(shí)值管跺。所以在第二次執(zhí)行 Block 表達(dá)式時(shí),即使已經(jīng)改變了局部變量 a 和 b 的值禾进,也不會(huì)影響 Block 表達(dá)式在執(zhí)行時(shí)所保存的局部變量的瞬時(shí)值豁跑。

這就是 Blocks 變量截獲局部變量值的特性。


5. 使用 __block 說(shuō)明符

實(shí)際上泻云,在使用 Block 表達(dá)式的時(shí)候艇拍,只能使用保存的局部變量的瞬時(shí)值,并不能直接對(duì)其進(jìn)行改寫宠纯。直接修改編譯器會(huì)直接報(bào)錯(cuò)卸夕,如下圖所示。

那么如果婆瓜,我們想要該寫 Block 表達(dá)式中截獲的局部變量的值快集,該怎么辦呢?

如果廉白,我們想在 Block 表達(dá)式中个初,改寫 Block 表達(dá)式之外聲明的局部變量,需要在該局部變量前加上 __block 的修飾符猴蹂。

這樣我們就能實(shí)現(xiàn):在 Block 表達(dá)式中院溺,為表達(dá)式外的局部變量賦值。

|

<pre style="font-family: consolas, Menlo, "PingFang SC", "Microsoft YaHei", monospace; font-size: 13px; overflow: auto; margin: 0px; padding: 10px; color: rgb(102, 102, 102); background: rgb(41, 41, 41); line-height: 1.6; border: none; text-align: right;">1
2
3
4
5
6
7
8
9
10
11
12
</pre>

|

<pre style="font-family: consolas, Menlo, "PingFang SC", "Microsoft YaHei", monospace; font-size: 13px; overflow: auto; margin: 0px; padding: 10px; color: rgb(234, 234, 234); background: rgb(0, 0, 0); line-height: 1.6; border: none; width: 498px;">// 使用 __block 說(shuō)明符修飾磅轻,更改局部變量值

  • (void)useBlockQualifierChangeLocalVariables {
    __block int a = 10, b = 20;
    void (^myLocalBlock)(void) = ^{
    a = 20;
    b = 30;

printf("a = %d, b = %d\n",a, b); // 打印結(jié)果:a = 20, b = 30
};

myLocalBlock();
}
</pre>

|

可以看到珍逸,使用 __block 說(shuō)明符修飾之后,我們?cè)?Block表達(dá)式中瓢省,成功的修改了局部變量值弄息。


6. Blocks 變量的循環(huán)引用以及如何避免

從上文中我們知道 Block 會(huì)對(duì)引用的局部變量進(jìn)行持有。同樣勤婚,如果 Block 也會(huì)對(duì)引用的對(duì)象進(jìn)行持有摹量,從而會(huì)導(dǎo)致相互持有,引起循環(huán)引用。

|

<pre style="font-family: consolas, Menlo, "PingFang SC", "Microsoft YaHei", monospace; font-size: 13px; overflow: auto; margin: 0px; padding: 10px; color: rgb(102, 102, 102); background: rgb(41, 41, 41); line-height: 1.6; border: none; text-align: right;">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
</pre>

|

<pre style="font-family: consolas, Menlo, "PingFang SC", "Microsoft YaHei", monospace; font-size: 13px; overflow: auto; margin: 0px; padding: 10px; color: rgb(234, 234, 234); background: rgb(0, 0, 0); line-height: 1.6; border: none; width: 321px;">/* —————— retainCycleBlcok.m —————— */

import <Foundation/Foundation.h>

import "Person.h"

int main() {
Person *person = [[Person alloc] init];
person.blk = ^{
NSLog(@"%@",person);
};

return 0;

}

/* —————— Person.h —————— */

import <Foundation/Foundation.h>

typedef void(^myBlock)(void);

@interface Person : NSObject
@property (nonatomic, copy) myBlock blk;
@end

/* —————— Person.m —————— */

import "Person.h"

@implementation Person

@end
</pre>

|

上面 retainCycleBlcok.mmain() 函數(shù)的代碼會(huì)導(dǎo)致一個(gè)問(wèn)題:person 持有成員變量 myBlock blk缨称,而 blk 也同時(shí)持有成員變量 person凝果,兩者互相引用,永遠(yuǎn)無(wú)法釋放睦尽。就造成了循環(huán)引用問(wèn)題器净。

那么,如何來(lái)解決這個(gè)問(wèn)題呢当凡?

6.1 ARC 下山害,通過(guò) __weak 修飾符來(lái)消除循環(huán)引用

在 ARC 下,可聲明附有 __weak 修飾符的變量沿量,并將對(duì)象賦值使用浪慌。

|

<pre style="font-family: consolas, Menlo, "PingFang SC", "Microsoft YaHei", monospace; font-size: 13px; overflow: auto; margin: 0px; padding: 10px; color: rgb(102, 102, 102); background: rgb(41, 41, 41); line-height: 1.6; border: none; text-align: right;">1
2
3
4
5
6
7
8
9
10
</pre>

|

<pre style="font-family: consolas, Menlo, "PingFang SC", "Microsoft YaHei", monospace; font-size: 13px; overflow: auto; margin: 0px; padding: 10px; color: rgb(234, 234, 234); background: rgb(0, 0, 0); line-height: 1.6; border: none; width: 342px;">int main() {
Person *person = [[Person alloc] init];
__weak typeof(person) weakPerson = person;

person.blk = ^{
    NSLog(@"%@",weakPerson);
};

return 0;

}
</pre>

|

這樣,通過(guò) __weak朴则,person 持有成員變量 myBlock blk权纤,而 blk 對(duì) person 進(jìn)行弱引用,從而就消除了循環(huán)引用乌妒。

6.2 MRC 下汹想,通過(guò) __block 修飾符來(lái)消除循環(huán)引用

MRC 下,是不支持 weak 修飾符的撤蚊。但是我們可以通過(guò) block 來(lái)消除循環(huán)引用古掏。

|

<pre style="font-family: consolas, Menlo, "PingFang SC", "Microsoft YaHei", monospace; font-size: 13px; overflow: auto; margin: 0px; padding: 10px; color: rgb(102, 102, 102); background: rgb(41, 41, 41); line-height: 1.6; border: none; text-align: right;">1
2
3
4
5
6
7
8
9
10
</pre>

|

<pre style="font-family: consolas, Menlo, "PingFang SC", "Microsoft YaHei", monospace; font-size: 13px; overflow: auto; margin: 0px; padding: 10px; color: rgb(234, 234, 234); background: rgb(0, 0, 0); line-height: 1.6; border: none; width: 356px;">int main() {
Person *person = [[Person alloc] init];
__block typeof(person) blockPerson = person;

person.blk = ^{
    NSLog(@"%@", blockPerson);
};

return 0;

}
</pre>

|

通過(guò) __block 引用的 blockPerson,是通過(guò)指針的方式來(lái)訪問(wèn) person拴魄,而沒(méi)有對(duì) person 進(jìn)行強(qiáng)引用冗茸,所以不會(huì)造成循環(huán)引用。


參考資料


以上是 iOS 開發(fā):『Blocks』詳盡總結(jié) (一)基本使用 的全部?jī)?nèi)容匹中,可以用來(lái)了解 Block夏漱,入門使用。下一篇我們通過(guò) Block 由 OC 代碼轉(zhuǎn)變的 C++ 源碼來(lái)抽絲剝繭的講一下 Block 的底層原理顶捷。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末挂绰,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子服赎,更是在濱河造成了極大的恐慌葵蒂,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,284評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件重虑,死亡現(xiàn)場(chǎng)離奇詭異践付,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)缺厉,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,115評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門熟史,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人鹿榜,你說(shuō)我怎么就攤上這事〔芸” “怎么了?”我有些...
    開封第一講書人閱讀 164,614評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵饲宛,是天一觀的道長(zhǎng)皆愉。 經(jīng)常有香客問(wèn)我,道長(zhǎng)艇抠,這世上最難降的妖魔是什么幕庐? 我笑而不...
    開封第一講書人閱讀 58,671評(píng)論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮练链,結(jié)果婚禮上翔脱,老公的妹妹穿的比我還像新娘。我一直安慰自己媒鼓,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,699評(píng)論 6 392
  • 文/花漫 我一把揭開白布错妖。 她就那樣靜靜地躺著绿鸣,像睡著了一般。 火紅的嫁衣襯著肌膚如雪暂氯。 梳的紋絲不亂的頭發(fā)上潮模,一...
    開封第一講書人閱讀 51,562評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音痴施,去河邊找鬼擎厢。 笑死,一個(gè)胖子當(dāng)著我的面吹牛辣吃,可吹牛的內(nèi)容都是我干的动遭。 我是一名探鬼主播,決...
    沈念sama閱讀 40,309評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼神得,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼厘惦!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起哩簿,我...
    開封第一講書人閱讀 39,223評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤宵蕉,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后节榜,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體羡玛,經(jīng)...
    沈念sama閱讀 45,668評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,859評(píng)論 3 336
  • 正文 我和宋清朗相戀三年宗苍,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了稼稿。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片薄榛。...
    茶點(diǎn)故事閱讀 39,981評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖渺杉,靈堂內(nèi)的尸體忽然破棺而出蛇数,到底是詐尸還是另有隱情,我是刑警寧澤是越,帶...
    沈念sama閱讀 35,705評(píng)論 5 347
  • 正文 年R本政府宣布耳舅,位于F島的核電站,受9級(jí)特大地震影響倚评,放射性物質(zhì)發(fā)生泄漏浦徊。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,310評(píng)論 3 330
  • 文/蒙蒙 一天梧、第九天 我趴在偏房一處隱蔽的房頂上張望盔性。 院中可真熱鬧,春花似錦呢岗、人聲如沸冕香。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,904評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)悉尾。三九已至,卻和暖如春挫酿,著一層夾襖步出監(jiān)牢的瞬間构眯,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,023評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工早龟, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留惫霸,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,146評(píng)論 3 370
  • 正文 我出身青樓葱弟,卻偏偏與公主長(zhǎng)得像壹店,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子翘悉,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,933評(píng)論 2 355

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