iOS之block淺談

前言

ios4.0系統(tǒng)已開始支持block属韧,在編程過程中述吸,block被Obj-C看成是對象,它封裝了一段代碼啥么,這段代碼可以在任何時候執(zhí)行。block可以作為函數(shù)參數(shù)或者函數(shù)的返回值贰逾,而其本身又可以帶輸入?yún)?shù)或返回值悬荣。它和傳統(tǒng)的函數(shù)指針很類似,但是有區(qū)別:block是inline的疙剑,并且它對局部變量是只讀的氯迂。

block和函數(shù)的相似性:(1)可以保存代碼(2)有返回值(3)有形參(4)調(diào)用方式一樣践叠。

block的使用

1、block的定義

// 聲明和實現(xiàn)寫在一起嚼蚀,就像變量的聲明實現(xiàn) int a = 10;

int(^aBlock)(int,int) = ^(intnum1,intnum2) {

returnnum1 * num2;

};

// 聲明和實現(xiàn)分開禁灼,就像變量先聲明后實現(xiàn) int a;a = 10;

int(^cBlock)(int,int);

cBlock = ^(intnum1,intnum2)

{

returnnum1 * num2;

};

其中,定義了一個名字為aBlock的blocks對象轿曙,并攜帶了相關(guān)信息:

1弄捕、aBlock 有兩個形式參數(shù),分別為int類型导帝;

2守谓、aBlock 的返回值為int 類型;

3您单、等式右邊就是blocks的具體實現(xiàn)分飞;

4、^ 帶邊blocks聲明和實現(xiàn)的標(biāo)示(關(guān)鍵字)睹限;

當(dāng)然譬猫,你可以定義其他形式的block。e.g:無返回值羡疗,無形式參數(shù)等染服;

void(^bBlock)() = ^()

{

inta =10;

printf(num = %d,a);

};

2、blocks 訪問權(quán)限

blocks可以訪問局部變量叨恨,但是不能修改柳刮。

inta =10;

int(^dBlock)(int) = ^(intnum)

{

a++;//not work!

returnnum * a;

};

此處不能修改的原因是在編譯期間確定的痒钝,編譯器編譯的時候把a的值復(fù)制到block作為一個新變量(假設(shè)是a‘ = 10)秉颗,此時a'和a是沒有關(guān)系的。

這個地方就是函數(shù)中的值傳遞送矩。如果要修改就要加關(guān)鍵字:__block或者static

__blockinta =7;

int(^dBlock)(int) = ^(intnum)

{

a++;// work蚕甥!

returnnum * a;

};

3、block的調(diào)用

block調(diào)用就像調(diào)用函數(shù)一樣栋荸。e.g:

1intc = aBlock(10,10);

bBlock();

4菇怀、block 應(yīng)用

假設(shè)我們熟悉代理遞值的話,對代理我們可能又愛有恨晌块!我們先建立模型A頁面 push

B頁面爱沟,如果把A頁面的值傳遞到B頁面,屬性和單例傳值可以搞定匆背!但是如果Pop過程中把B頁面的值傳遞到A頁面呼伸,那就可以用單例或者代理了!說到代理钝尸,

我們要先聲明協(xié)議括享,創(chuàng)建代理闽铐,很是麻煩。常常我們傳遞一個數(shù)值需要在兩個頁面間寫很多代碼奶浦,這些代碼改變頁面的整體順序兄墅,可讀性也打了折扣。所以澳叉,此

時隙咸,block是一種優(yōu)化方案!

5成洗、 block的內(nèi)存管理

block本身是像對象一樣可以retain五督,和release。但是瓶殃,block在創(chuàng)建的時候充包,它的內(nèi)存是分配在棧(stack)上,而不是在堆(heap)上遥椿。他本身的作于域是屬于創(chuàng)建時候的作用域基矮,一旦在創(chuàng)建時候的作用域外面調(diào)用block將導(dǎo)致程序崩潰。比如下面的例子冠场。 我在view did load中創(chuàng)建了一個block:

- (void)viewDidLoad

{

[superviewDidLoad];

int number = 1;

_block = ^(){

NSLog(@number %d, number);

};

}

并且在一個按鈕的事件中調(diào)用了這個block:

- (IBAction)testDidClick:(id)sender {

_block();

}

此時我按了按鈕之后就會導(dǎo)致程序崩潰家浇,解決這個問題的方法就是在創(chuàng)建完block的時候需要調(diào)用copy的方法。copy會把block從棧上移動到堆上碴裙,那么就可以在其他地方使用這個block了~ 修改代碼如下:

_block = ^(){

NSLog(@number %d, number);

};

_block = [_blockcopy];

同理钢悲,特別需要注意的地方就是在把block放到集合類當(dāng)中去的時候,如果直接把生成的block放入到集合類中舔株,是無法在其他地方使用block莺琳,必須要對block進(jìn)行copy。不過代碼看上去相對奇怪一些:

[array addObject:[[^{

NSLog(@hello!);

} copy] autorelease]];

6载慈、循環(huán)引用

對于非ARC下, 為了防止循環(huán)引用, 我們使用__block來修飾在Block中使用的對象:

對于ARC下, 為了防止循環(huán)引用, 我們使用__weak來修飾在Block中使用的對象惭等。原理就是:ARC中,Block中如果引用了__strong修飾符的自動變量娃肿,則相當(dāng)于Block對該變量的引用計數(shù)+1咕缎。

這一點其實是在第一點的一個小的衍生珠十。當(dāng)在block內(nèi)部使用成員變量的時候料扰,比如


@interface ViewController : UIViewController

{

NSString *_string;

}

@end

在block創(chuàng)建中:

_block = ^(){

NSLog(@string %@, _string);

};

這里的_string相當(dāng)于是self->_string;那么block是會對內(nèi)部的對象進(jìn)行一次retain焙蹭。也就是說晒杈,self會被retain一次。當(dāng)self釋放的時候孔厉,需要block釋放后才會對self進(jìn)行釋放拯钻,但是block的釋放又需要等self的dealloc中才會釋放帖努。如此一來變形成了循環(huán)引用,導(dǎo)致內(nèi)存泄露粪般。

修改方案是新建一個__block scope的局部變量拼余,并把self賦值給它,而在block內(nèi)部則使用這個局部變量來進(jìn)行取值亩歹。因為__block標(biāo)記的變量是不會被自動retain的匙监。

__block ViewController *controller = self;

_block = ^(){

NSLog(@string %@, controller->_string);

};

博主瀏覽了很多博客,總結(jié)了一下小作,block實際上是(底層c++): 指向結(jié)構(gòu)體的指針亭姥,底層會創(chuàng)建一個結(jié)構(gòu)體,實現(xiàn)構(gòu)造方法顾稀,來接參數(shù)达罗,編譯器會將block的內(nèi)部代碼生成對應(yīng)的函數(shù)。

block實戰(zhàn):用block進(jìn)行頁面間傳值

使用Block的地方很多静秆,其中傳值只是其中的一小部分粮揉,下面介紹Block在兩個界面之間的傳值:

先說一下思想:

首先,創(chuàng)建兩個視圖控制器抚笔,在第一個視圖控制器中創(chuàng)建一個UILabel和一個UIButton滔蝉,其中UILabel是為了顯示第二個視圖控制器傳過來的字符串,UIButton是為了push到第二個界面塔沃。

第二個界面的只有一個UITextField蝠引,是為了輸入文字,當(dāng)輸入文字蛀柴,并且返回第一個界面的時候螃概,當(dāng)?shù)诙€視圖將要消失的時候,就將第二個界面上TextFiled中的文字傳給第一個界面鸽疾,并且顯示在UILabel上吊洼。

其實核心代碼就幾行代碼:

下面是主要代碼:(因為我是用storyBoard創(chuàng)建的工程,所以上面的屬性和相應(yīng)的方法制肮,是使用系統(tǒng)生成的outlet)

一冒窍、在第二個視圖控制器的.h文件中定義聲明Block屬性

typedef void(^ReturnTextBlock)(NSString *showText);

@interface TextFieldViewController : UIViewController

@property(nonatomic, copy) ReturnTextBlock returnTextBlock;

- (void)returnText:(ReturnTextBlock)block;

@end

第一行代碼是為要聲明的Block重新定義了一個名字

ReturnTextBlock

這樣,下面在使用的時候就會很方便豺鼻。

第三行是定義的一個Block屬性

第四行是一個在第一個界面?zhèn)鬟M(jìn)來一個Block語句塊的函數(shù)综液,不用也可以,不過加上會減少代碼的書寫量

二儒飒、實現(xiàn)第二個視圖控制器的方法

- (void)returnText:(ReturnTextBlock)block {

self.returnTextBlock = block;

}

- (void)viewWillDisappear:(BOOL)animated {

if(self.returnTextBlock != nil) {

self.returnTextBlock(self.inputTF.text);

}

}

其中inputTF是視圖中的UITextField谬莹。

第一個方法就是定義的那個方法,把傳進(jìn)來的Block語句塊保存到本類的實例變量returnTextBlock(.h中定義的屬性)中,然后尋找一個時機調(diào)用附帽,而這個時機就是上面說到的埠戳,當(dāng)視圖將要消失的時候,需要重寫:

- (void)viewWillDisappear:(BOOL)animated;

方法蕉扮。

三整胃、在第一個視圖中獲得第二個視圖控制器,并且用第二個視圖控制器來調(diào)用定義的屬性

如下方法中書寫:

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender

{

// Get the new view controller using [segue destinationViewController].

// Pass the selected object to the new view controller.

TextFieldViewController *tfVC = segue.destinationViewController;

[tfVC returnText:^(NSString *showText) {

self.showLabel.text = showText;

}];

}

揭開block神秘面紗

假設(shè)A有一個任務(wù)喳钟,是去倉庫取一張A4紙放到會議室爪模,然后在紙上寫一份策劃書舌菜。取紙又要經(jīng)過倉庫管理員吩屹,于是A通知倉庫管理員來張紙過來。由于管理員是個老

頭動作很慢陕壹,另外A還有其他工作应狱,如果一直等待管理員就太浪費時間了共郭,合理的做法是讓倉庫管理員進(jìn)行取紙這項工作,A在通知管理員后就繼續(xù)自己的工作疾呻。A

不知道倉庫管理員什么時候能完成取紙除嘹,也就不知道什么時候可以在紙上寫策劃書。這時block機制就派上用場了岸蜗,使用這種機制尉咕,可以讓A在通知倉庫管理員

取紙的同時,告訴倉庫管理員將紙放到編號XX會議室璃岳,并安排好將要在紙上寫的策劃內(nèi)容年缎,當(dāng)管理員把紙拿來后,可能過一會就會有個助理將策劃內(nèi)容寫到紙上铃慷。

我們將這個故事對應(yīng)到代碼上:

#pragma?mark?-?第三方登錄

-?(void)btnLoginWeiboClicked:(id)sender?{

[_waitCirclestartAnimating];

[[HSLoginClasscreateInstance]loginWithPlatformType:ShareTypeSinaWeibowithBlock:^(BOOLsuccess,idmessage)?{

if(success)?{

//跳出登錄頁面

[selfdismissViewControllerAnimated:YEScompletion:^{}];

[_waitCirclestopAnimating];

NSLog(@"新浪微博?%@",?message);

}else{

}

}];

//test?statistics

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0),?^{

NSDate*?date?=?[NSDatedate];

NSTimeInterval?nowTime?=?[datetimeIntervalSince1970];

NSString*?netStatus?=?(NSString*)[[NSUserDefaultsstandardUserDefaults]objectForKey:NETSTATUS];

[[HSStatisticsModulestatisticsModule]makeSession:nowTime?:OPER_IN?:@"noid"];

[[HSStatisticsModulestatisticsModule]upLoadData:netStatus?:[NSStringstringWithFormat:@"%f",nowTime]];

});

}

請看這段代碼单芜,整個方法是A要做的工作,startAnimating/loginWithPlatformType/dispatch_async分別是A要做的三個任務(wù)犁柜,由于loginWithPlatformType需要一段時間才能完成洲鸠,并且loginWithPlatformType完成后要根據(jù)結(jié)果做相應(yīng)處理,所以我們對loginWithPlatformType進(jìn)行異步處理馋缅。block代碼段是loginWithPlatformType得到結(jié)果后要做的操作H扒腕,這里的block寫法就表示,我們先將操作H安排好萤悴,然后繼續(xù)其他工作瘾腰,當(dāng)loginWithPlatformType執(zhí)行ok后自會有人(可能是那個助理)去執(zhí)行操作H。

iOS面試之block

1 什么是block

對于閉包(block),

有很多定義稚疹,其中閉包就是能夠讀取其它函數(shù)內(nèi)部變量的函數(shù)居灯,這個定義即接近本質(zhì)又較好理解祭务。對于剛接觸Block的同學(xué)内狗,會覺得有些繞怪嫌,因為我們習(xí)慣寫這

樣的程序main(){ funA();} funA(){funB();} funB(){.....};

就是函數(shù)main調(diào)用函數(shù)A,函數(shù)A調(diào)用函數(shù)B...

函數(shù)們依次順序執(zhí)行柳沙,但現(xiàn)實中不全是這樣的岩灭,例如項目經(jīng)理M,手下有3個程序員A赂鲤、B噪径、C,當(dāng)他給程序員A安排實現(xiàn)功能F1時数初,他并不等著A完成之后找爱,再

去安排B去實現(xiàn)F2,而是安排給A功能F1泡孩,B功能F2车摄,C功能F3,然后可能去寫技術(shù)文檔仑鸥,而當(dāng)A遇到問題時吮播,他會來找項目經(jīng)理M,當(dāng)B做完時眼俊,會通知

M意狠,這就是一個異步執(zhí)行的例子。在這種情形下疮胖,Block便可大顯身手环戈,因為在項目經(jīng)理M,給A安排工作時澎灸,同時會告訴A若果遇到困難谷市,如何能找到他報告

問題(例如打他手機號),這就是項目經(jīng)理M給A的一個回調(diào)接口击孩,要回掉的操作迫悠,比如接到電話,百度查詢后巩梢,返回網(wǎng)頁內(nèi)容給A创泄,這就是一個Block,在M

交待工作時括蝠,已經(jīng)定義好鞠抑,并且取得了F1的任務(wù)號(局部變量),卻是在當(dāng)A遇到問題時忌警,才調(diào)用執(zhí)行搁拙,跨函數(shù)在項目經(jīng)理M查詢百度秒梳,獲得結(jié)果后回調(diào)該

block。

2 block 實現(xiàn)原理

Objective-C是對C語言的擴展箕速,block的實現(xiàn)是基于指針和函數(shù)指針酪碘。

從計算語言的發(fā)展,最早的goto盐茎,高級語言的指針兴垦,到面向?qū)ο笳Z言的block,從機器的思維字柠,一步步接近人的思維探越,以方便開發(fā)人員更為高效、直接的描述出現(xiàn)實的邏輯(需求)窑业。

下面是兩篇很好的介紹block實現(xiàn)的博文

iOS中block實現(xiàn)的探究

談Objective-C Block的實現(xiàn)

3 block的使用

使用實例

cocoaTouch框架下動畫效果的Block的調(diào)用

使用typed聲明block

typedef void(^didFinishBlock) (NSObject *ob);

這就聲明了一個didFinishBlock類型的block钦幔,

然后便可用

@property (nonatomic,copy) didFinishBlock? finishBlock;

聲明一個block對象,注意對象屬性設(shè)置為copy常柄,接到block 參數(shù)時鲤氢,便會自動復(fù)制一份。

__block是一種特殊類型拐纱,

使用該關(guān)鍵字聲明的局部變量铜异,可以被block所改變,并且其在原函數(shù)中的值會被改變秸架。

4 常見系列面試題

面試時揍庄,面試官會先問一些,是否了解block东抹,是否使用過block蚂子,這些問題相當(dāng)于開場白,往往是下面一系列問題的開始缭黔,所以一定要如實根據(jù)自己的情況回答食茎。

1 使用block和使用delegate完成委托模式有什么優(yōu)點?

首先要了解什么是委托模式馏谨,委托模式在iOS中大量應(yīng)用别渔,其在設(shè)計模式中是適配器模式中的對象適配器,Objective-C中使用id類型指向一切對象惧互,使委托模式在iOS中的實現(xiàn)更為方便哎媚。了解委托模式的細(xì)節(jié):

iOS設(shè)計模式----委托模式

使用block實現(xiàn)委托模式,其優(yōu)點是回調(diào)的block代碼塊定義在委托對象函數(shù)內(nèi)部喊儡,使代碼更為緊湊拨与;

適配對象不再需要實現(xiàn)具體某個protocol,代碼更為簡潔艾猜。

2 多線程與block

GCD與Block

使用 dispatch_async系列方法买喧,可以以指定的方式執(zhí)行block

GCD編程實例

dispatch_async的完整定義

void dispatch_async(

dispatch_queue_t queue,

dispatch_block_t block);

功能:在指定的隊列里提交一個異步執(zhí)行的block捻悯,不阻塞當(dāng)前線程

通過queue來控制block執(zhí)行的線程。主線程執(zhí)行前文定義的 finishBlock對象

dispatch_async(dispatch_get_main_queue(),^(void){finishBlock();});

參考博客:

http://blog.csdn.net/xunyn/article/details/11658261

http://www.2cto.com/kf/201504/388349.html

博主的微博淤毛、CocoaChina博客今缚、CSDN博客同步更新,歡迎關(guān)注:

新浪微博:http://weibo.com/p/1005052308506177/home?from=page_100505_profile&wvr=6&mod=data&is_all=1#place

CocoaChina:http://blog.cocoachina.com/477998

CSDN:http://blog.csdn.net/czkyes

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末钱床,一起剝皮案震驚了整個濱河市荚斯,隨后出現(xiàn)的幾起案子埠居,更是在濱河造成了極大的恐慌查牌,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,378評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件滥壕,死亡現(xiàn)場離奇詭異纸颜,居然都是意外死亡,警方通過查閱死者的電腦和手機绎橘,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,356評論 2 382
  • 文/潘曉璐 我一進(jìn)店門胁孙,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人称鳞,你說我怎么就攤上這事涮较。” “怎么了冈止?”我有些...
    開封第一講書人閱讀 152,702評論 0 342
  • 文/不壞的土叔 我叫張陵狂票,是天一觀的道長。 經(jīng)常有香客問我熙暴,道長闺属,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,259評論 1 279
  • 正文 為了忘掉前任周霉,我火速辦了婚禮掂器,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘俱箱。我一直安慰自己国瓮,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 64,263評論 5 371
  • 文/花漫 我一把揭開白布狞谱。 她就那樣靜靜地躺著乃摹,像睡著了一般。 火紅的嫁衣襯著肌膚如雪芋簿。 梳的紋絲不亂的頭發(fā)上峡懈,一...
    開封第一講書人閱讀 49,036評論 1 285
  • 那天,我揣著相機與錄音与斤,去河邊找鬼肪康。 笑死荚恶,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的磷支。 我是一名探鬼主播谒撼,決...
    沈念sama閱讀 38,349評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼雾狈!你這毒婦竟也來了廓潜?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,979評論 0 259
  • 序言:老撾萬榮一對情侶失蹤善榛,失蹤者是張志新(化名)和其女友劉穎辩蛋,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體移盆,經(jīng)...
    沈念sama閱讀 43,469評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡悼院,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,938評論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了咒循。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片据途。...
    茶點故事閱讀 38,059評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖叙甸,靈堂內(nèi)的尸體忽然破棺而出颖医,到底是詐尸還是另有隱情,我是刑警寧澤裆蒸,帶...
    沈念sama閱讀 33,703評論 4 323
  • 正文 年R本政府宣布熔萧,位于F島的核電站,受9級特大地震影響光戈,放射性物質(zhì)發(fā)生泄漏哪痰。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,257評論 3 307
  • 文/蒙蒙 一久妆、第九天 我趴在偏房一處隱蔽的房頂上張望晌杰。 院中可真熱鬧,春花似錦筷弦、人聲如沸肋演。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,262評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽爹殊。三九已至,卻和暖如春奸绷,著一層夾襖步出監(jiān)牢的瞬間梗夸,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評論 1 262
  • 我被黑心中介騙來泰國打工号醉, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留反症,地道東北人辛块。 一個月前我還...
    沈念sama閱讀 45,501評論 2 354
  • 正文 我出身青樓,卻偏偏與公主長得像铅碍,于是被迫代替她去往敵國和親润绵。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,792評論 2 345

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

  • *面試心聲:其實這些題本人都沒怎么背,但是在上海 兩周半 面了大約10家 收到差不多3個offer,總結(jié)起來就是把...
    Dove_iOS閱讀 27,125評論 29 470
  • 多線程胞谈、特別是NSOperation 和 GCD 的內(nèi)部原理尘盼。運行時機制的原理和運用場景。SDWebImage的原...
    LZM輪回閱讀 2,004評論 0 12
  • iOS面試小貼士 ———————————————回答好下面的足夠了------------------------...
    不言不愛閱讀 1,962評論 0 7
  • 史上最全的iOS面試題及答案 iOS面試小貼士———————————————回答好下面的足夠了----------...
    Style_偉閱讀 2,345評論 0 35
  • __block和__weak修飾符的區(qū)別其實是挺明顯的:1.__block不管是ARC還是MRC模式下都可以使用烦绳,...
    LZM輪回閱讀 3,284評論 0 6