iOS中block的使用

#Block

###Block概述

Block它是C語言級(jí)別和運(yùn)行時(shí)方面的一個(gè)特征鸯隅。Block封裝了一段代碼邏輯酵颁,也用{}括起蝎亚,和標(biāo)準(zhǔn)C語言中的函數(shù)/函數(shù)指針很相似澄暮,此外就是blokc能夠?qū)Χx環(huán)境中的變量可以引用到名段。這一點(diǎn)和其它各種語言中所說的“閉包”是非常類似的概念。在iOS中泣懊,block有很多應(yīng)用場景伸辟,比如對(duì)代碼封裝作為參數(shù)傳遞。這在使用dispatch并發(fā)(Operation中也有BlockOperation)和completion異步回調(diào)等處都廣泛應(yīng)用馍刮。

-Block是蘋果官方特別推薦使用的數(shù)據(jù)類型信夫,使用場景比較廣泛

-動(dòng)畫

-多線程

-集合遍歷

-網(wǎng)絡(luò)請(qǐng)求回調(diào)

-Block的作用

-用來保存某一段代碼,可以在恰當(dāng)時(shí)候再去出來調(diào)用

-功能類似于函數(shù)和方法

1.Block的基本使用

```

聲明:(返回類型)(^聲明的block名稱)(參數(shù)列表);

實(shí)現(xiàn):^(參數(shù)列表){代碼塊}

返回值類型(^block變量名)(參數(shù)列表) = ^(形參列表) {

}卡啰;

```

賦值的例子:

```objc

intsum(intvalue1,intvalue2)

{

returnvalue1 + value2;

}

intmain(intargc,constchar* argv[]) {

@autoreleasepool {

int(*sumP)(int,int);

sumP = sum;

NSLog(@"sum = %i",sumP(10,20));

int(^sumBlock) (intvalue1,intvalue2) = ^(intvalue1,intvalue2) {

returnvalue2 + value1;

};

NSLog(@"sum----%i",sumBlock(10,30));

}

return0;

}

```

其實(shí)Block和C語言中的指向函數(shù)的指針差不多

其實(shí)我們完全可以定義C語言的函數(shù)静稻,如下所示

```objc

intsum(intvalue1,intvalue2)

{

returnvalue1 + value2;

}

intmain(intargc,constchar* argv[]) {

@autoreleasepool {

int(*sumP)(int,int);

sumP = sum;

NSLog(@"sum = %i",sumP(10,20));

}

return0;

}

```

有時(shí)為了方便,用typedef給出定義匈辱,在蘋果的官方文檔里振湾,建議出現(xiàn)多次的block使用typedef定義。

而block的調(diào)用亡脸,則十分簡單:block名稱(參數(shù)列表);

2.使用中的注意點(diǎn)

-block中可以定義和外界同名的變量押搪,并且如果在block中定義了和外界同名的變量,在block中訪問的是block內(nèi)部的變量

-默認(rèn)情況下浅碾,在block內(nèi)部不能改變外面變量的值

-因?yàn)閎lock中變量和外面的變量并不是同一個(gè)變量大州,可以通過打打印變量的地址看出來

-如果block中訪問到了外界的變量,block會(huì)將外界變量拷貝一份到堆內(nèi)存中

-因?yàn)閎lock中使用的外面變量的值是拷貝過來的即值拷貝垂谢,所以在調(diào)用之前修改外界變量的值厦画,不會(huì)影響到block中拷貝的值

-如果想在block中修改外界變量的值,必須在外界變量前面加上`__block`

-如果在block中修改了外界變量的值埂陆,會(huì)影響到外界變量的值苛白,

我們可以把.m反編譯成c++文件,看看其內(nèi)部是怎么實(shí)現(xiàn)`__block`這個(gè)關(guān)鍵詞可以修改外部變量的

```cpp

intsum(intvalue1,intvalue2)

{

returnvalue1 + value2;

}

struct__main_block_impl_0 {

struct__block_impl impl;

struct__main_block_desc_0* Desc;

__main_block_impl_0(void*fp,struct__main_block_desc_0 *desc,intflags=0) {

impl.isa = &_NSConcreteStackBlock;

impl.Flags = flags;

impl.FuncPtr = fp;

Desc = desc;

}

};

staticint__main_block_func_0(struct__main_block_impl_0 *__cself,intvalue1,intvalue2) {

returnvalue2 + value1;

}

staticstruct__main_block_desc_0 {

size_t reserved;

size_t Block_size;

} __main_block_desc_0_DATA = {0,sizeof(struct__main_block_impl_0)};

intmain(intargc,constchar* argv[]) {

/* @autoreleasepool */{ __AtAutoreleasePool __autoreleasepool;

int(*sumP)(int,int);

sumP = sum;

NSLog((NSString *)&__NSConstantStringImpl__var_folders_8b_skbhgyln78718lwjds4398k80000gn_T_main_185299_mi_0,sumP(10,20));

int(*sumBlock) (intvalue1,intvalue2) = ((int(*)(int,int))&__main_block_impl_0((void*)__main_block_func_0, &__main_block_desc_0_DATA));

NSLog((NSString *)&__NSConstantStringImpl__var_folders_8b_skbhgyln78718lwjds4398k80000gn_T_main_185299_mi_1,((int(*)(__block_impl *,int,int))((__block_impl *)sumBlock)->FuncPtr)((__block_impl *)sumBlock,10,30));

}

return0;

}

staticstructIMAGE_INFO {unsignedversion;unsignedflag; } _OBJC_IMAGE_INFO = {0,2};

```

加上__block

```cpp

intsum(intvalue1,intvalue2)

{

returnvalue1 + value2;

}

struct__Block_byref_a_0 {

void*__isa;

__Block_byref_a_0 *__forwarding;

int__flags;

int__size;

inta;

};

struct__main_block_impl_0 {

struct__block_impl impl;

struct__main_block_desc_0* Desc;

__Block_byref_a_0 *a;// by ref

__main_block_impl_0(void*fp,struct__main_block_desc_0 *desc, __Block_byref_a_0 *_a,intflags=0) : a(_a->__forwarding) {

impl.isa = &_NSConcreteStackBlock;

impl.Flags = flags;

impl.FuncPtr = fp;

Desc = desc;

}

};

staticint__main_block_func_0(struct__main_block_impl_0 *__cself,intvalue1,intvalue2) {

__Block_byref_a_0 *a = __cself->a;// bound by ref

(a->__forwarding->a) =20;

returnvalue2 + value1;

}

staticvoid__main_block_copy_0(struct__main_block_impl_0*dst,struct__main_block_impl_0*src) {_Block_object_assign((void*)&dst->a, (void*)src->a,8/*BLOCK_FIELD_IS_BYREF*/);}

staticvoid__main_block_dispose_0(struct__main_block_impl_0*src) {_Block_object_dispose((void*)src->a,8/*BLOCK_FIELD_IS_BYREF*/);}

staticstruct__main_block_desc_0 {

size_t reserved;

size_t Block_size;

void(*copy)(struct__main_block_impl_0*,struct__main_block_impl_0*);

void(*dispose)(struct__main_block_impl_0*);

} __main_block_desc_0_DATA = {0,sizeof(struct__main_block_impl_0), __main_block_copy_0, __main_block_dispose_0};

intmain(intargc,constchar* argv[]) {

/* @autoreleasepool */{ __AtAutoreleasePool __autoreleasepool;

int(*sumP)(int,int);

sumP = sum;

NSLog((NSString *)&__NSConstantStringImpl__var_folders_8b_skbhgyln78718lwjds4398k80000gn_T_main_9f1f9e_mi_0,sumP(10,20));

__attribute__((__blocks__(byref))) __Block_byref_a_0 a = {(void*)0,(__Block_byref_a_0 *)&a,0,sizeof(__Block_byref_a_0),10};

int(*sumBlock) (intvalue1,intvalue2) = ((int(*)(int,int))&__main_block_impl_0((void*)__main_block_func_0, &__main_block_desc_0_DATA, (__Block_byref_a_0 *)&a,570425344));

NSLog((NSString *)&__NSConstantStringImpl__var_folders_8b_skbhgyln78718lwjds4398k80000gn_T_main_9f1f9e_mi_1,((int(*)(__block_impl *,int,int))((__block_impl *)sumBlock)->FuncPtr)((__block_impl *)sumBlock,10,30));

}

return0;

}

staticstructIMAGE_INFO {unsignedversion;unsignedflag; } _OBJC_IMAGE_INFO = {0,2};

```

很明顯加上了__block之后傳入的是&這樣的焚虱,是把地址傳到block內(nèi)部去了,所以可以修改外部變量了

-block是存儲(chǔ)在堆中還是棧中呢

-默認(rèn)情況下block是存儲(chǔ)在棧中的懂版,如果對(duì)block進(jìn)行一個(gè)copy操作鹃栽,block會(huì)轉(zhuǎn)移到堆中

-如果block在棧中,block中訪問了外界的對(duì)象,那么不會(huì)對(duì)對(duì)象進(jìn)行retain操作

-但是如果block在堆中民鼓,block中訪問了外面的對(duì)象薇芝,那么會(huì)對(duì)外界的對(duì)象進(jìn)行一次retain操作

-如果block中訪問了外界的對(duì)象,一定要給對(duì)象加上__block丰嘉,只要加上__block夯到,哪怕block在堆中,也不會(huì)對(duì)外界的對(duì)象進(jìn)行retain

-想把block弄到堆中可以使用`Clock_copy()`

###有如下一些注意點(diǎn):

對(duì)定義環(huán)境的變量使用饮亏。默認(rèn)是以const的方式使用耍贾,這有點(diǎn)像函數(shù)的const參數(shù)傳遞,如過需要block內(nèi)修改可變路幸,則使用__block荐开,這樣做存儲(chǔ)就實(shí)現(xiàn)了共享,包括塊中的遞歸應(yīng)用和定義環(huán)境上下文中的多個(gè)block使用简肴。block通常定義在棧幀當(dāng)中晃听,而當(dāng)所處的棧幀被銷毀的時(shí)候,block以及引用到的__block變量將會(huì)依然有效砰识。

引用類型問題能扒。block中的引用默認(rèn)都是強(qiáng)引用,必要的時(shí)候需要使用__weak辫狼,同delegate使用的注意一樣初斑,避免循環(huán)引用。此外予借,蘋果文檔中還給出了對(duì)instanceVariable和對(duì)localVariable引用不同的例子越平,注意體會(huì)下。

copy灵迫。在類屬性中秦叛,要使用copy。此外瀑粥,對(duì)block進(jìn)行copy要使用Block_copy()/Block_release()挣跋。

蘋果文檔中幾種需要避免使用的方式∧唬《Blocks Programming Topics》中Using Blocks中的例子避咆,實(shí)際上就是要注意block定義的位置與其上下文的關(guān)系。

有關(guān)Block的地址/引用修噪。注意這篇文章中最后例子中的問題:http://www.cnblogs.com/kesalin/archive/2013/04/30/ios_block.html我的理解是Block的地址發(fā)生了變化查库,最終的問題是對(duì)Block引用地址釋放時(shí)的野指針錯(cuò)誤。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末黄琼,一起剝皮案震驚了整個(gè)濱河市樊销,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖围苫,帶你破解...
    沈念sama閱讀 217,277評(píng)論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件裤园,死亡現(xiàn)場離奇詭異,居然都是意外死亡剂府,警方通過查閱死者的電腦和手機(jī)拧揽,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,689評(píng)論 3 393
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來腺占,“玉大人淤袜,你說我怎么就攤上這事⊥宓眩” “怎么了饮怯?”我有些...
    開封第一講書人閱讀 163,624評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長嚎研。 經(jīng)常有香客問我蓖墅,道長,這世上最難降的妖魔是什么临扮? 我笑而不...
    開封第一講書人閱讀 58,356評(píng)論 1 293
  • 正文 為了忘掉前任论矾,我火速辦了婚禮,結(jié)果婚禮上杆勇,老公的妹妹穿的比我還像新娘贪壳。我一直安慰自己,他們只是感情好蚜退,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,402評(píng)論 6 392
  • 文/花漫 我一把揭開白布闰靴。 她就那樣靜靜地躺著,像睡著了一般钻注。 火紅的嫁衣襯著肌膚如雪蚂且。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,292評(píng)論 1 301
  • 那天幅恋,我揣著相機(jī)與錄音杏死,去河邊找鬼。 笑死捆交,一個(gè)胖子當(dāng)著我的面吹牛淑翼,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播品追,決...
    沈念sama閱讀 40,135評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼玄括,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了肉瓦?” 一聲冷哼從身側(cè)響起惠豺,我...
    開封第一講書人閱讀 38,992評(píng)論 0 275
  • 序言:老撾萬榮一對(duì)情侶失蹤银还,失蹤者是張志新(化名)和其女友劉穎风宁,沒想到半個(gè)月后洁墙,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,429評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡戒财,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,636評(píng)論 3 334
  • 正文 我和宋清朗相戀三年热监,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片饮寞。...
    茶點(diǎn)故事閱讀 39,785評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡孝扛,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出幽崩,到底是詐尸還是另有隱情苦始,我是刑警寧澤,帶...
    沈念sama閱讀 35,492評(píng)論 5 345
  • 正文 年R本政府宣布慌申,位于F島的核電站陌选,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏蹄溉。R本人自食惡果不足惜咨油,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,092評(píng)論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望柒爵。 院中可真熱鬧役电,春花似錦、人聲如沸棉胀。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,723評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽唁奢。三九已至霎挟,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間驮瞧,已是汗流浹背氓扛。 一陣腳步聲響...
    開封第一講書人閱讀 32,858評(píng)論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留论笔,地道東北人采郎。 一個(gè)月前我還...
    沈念sama閱讀 47,891評(píng)論 2 370
  • 正文 我出身青樓,卻偏偏與公主長得像狂魔,于是被迫代替她去往敵國和親蒜埋。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,713評(píng)論 2 354

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

  • 前言 Blocks是C語言的擴(kuò)充功能最楷,而Apple 在OS X Snow Leopard 和 iOS 4中引入了這...
    小人不才閱讀 3,768評(píng)論 0 23
  • 摘要block是2010年WWDC蘋果為Objective-C提供的一個(gè)新特性整份,它為我們開發(fā)提供了便利待错,比如GCD...
    西門吹雪123閱讀 916評(píng)論 0 4
  • Blocks Blocks Blocks 是帶有局部變量的匿名函數(shù) 截取自動(dòng)變量值 int main(){ ...
    南京小伙閱讀 929評(píng)論 1 3
  • Block基礎(chǔ)回顧 1.什么是Block? 帶有局部變量的匿名函數(shù)(名字不重要烈评,知道怎么用就行)火俄,差不多就與C語言...
    Bugfix閱讀 6,766評(píng)論 5 61
  • 1.1 局部變量 局部自動(dòng)變量,在Block中可被讀取讲冠。Block定義時(shí)copy變量的值瓜客,在Block中作為常量使...
    陳雨塵閱讀 2,933評(píng)論 4 31