亚洲免费av电影一区二区三区,日韩爱爱视频,51精品视频一区二区三区,91视频爱爱,日韩欧美在线播放视频,中文字幕少妇AV,亚洲电影中文字幕,久久久久亚洲av成人网址,久久综合视频网站,国产在线不卡免费播放

        ?

        Block分析

        2016-12-21 07:20:53許莉鑫金海佳李瑪田英愛
        數(shù)碼世界 2016年12期
        關(guān)鍵詞:聲明自動變量

        許莉鑫 金海佳 李瑪 田英愛

        北京信息科技大學(xué)計(jì)算機(jī)學(xué)院

        Block分析

        許莉鑫 金海佳 李瑪 田英愛

        北京信息科技大學(xué)計(jì)算機(jī)學(xué)院

        Block是蘋果公司在iOS4后引入的對C語言的擴(kuò)展。把Block的功能概括來說,即帶有自動變量(即局部變量)的匿名函數(shù)指針。本文將對Block在這幾個方面進(jìn)行解讀:一、Block的語法。二、Block作為函數(shù)參數(shù)使用的方法。三、Block對自動變量的截獲。四、__Block說明符、存儲域。五、循環(huán)引用導(dǎo)致內(nèi)存泄漏的問題。本文旨在使閱讀者深入認(rèn)識Block并更好地使用Block。

        Block Objective-C iOS

        1 引言

        在編程中閉包是非常常見的一種技術(shù)手段,在Objective-C中被稱做Block。Block因其簡潔的語法,特殊的存儲方式,被廣泛地使用在Objective-C工程中。很好地使用Block并不簡單,本文將針對Block進(jìn)行深入分析。

        Block本質(zhì)是一個函數(shù)指針,它的使用方法和C語言函數(shù)指針一樣,可以傳入?yún)?shù),且有返回值。但和函數(shù)指針相比,Block功能更強(qiáng)大,所以Block也復(fù)雜很多,它與函數(shù)指針的區(qū)別主要表現(xiàn)在以下方面:語法上存在區(qū)別、Block是一個匿名指針、Block會截獲自動變量、內(nèi)存管理與釋放的區(qū)別。

        2 Block語法

        2.1 聲明Block

        在C語言中,可以將一個函數(shù)的地址賦值給函數(shù)指針類型變量中,形式如:

        int functionName(int count){

        return count;

        因?yàn)锽lock本質(zhì)是一個匿名函數(shù)指針,所以聲明一個Block和C語言中聲明函數(shù)指針十分類似,形式如:

        與C語言中聲明函數(shù)指針相比,聲明Block的區(qū)別即將“*”替換成。

        Block類型變量和一般的C語言變量的使用方法完全相同,它可作為自動變量、函數(shù)參數(shù)、靜態(tài)變量、靜態(tài)全局變量、全局變量等使用。

        2.2 對Block賦值

        形式如:

        “^”符號表明這是一個Block,“^”后的括號中包含著參數(shù),花括號中可以進(jìn)行一些操作,并根據(jù)需要在確定時候返回。

        2.3 使用Block

        可以像使用一個C語言函數(shù)一樣來使用Block:

        int count = blo(10);

        3 Block可作為函數(shù)參數(shù)

        Block比C語言中的函數(shù)強(qiáng)大,比如Block可以作為函數(shù)參數(shù)。可以用以下方式聲明一個Objective-C的方法:

        然后以以下方式調(diào)用這個方法:

        這里hander變成了回調(diào),事實(shí)上Apple的大量api接口也是這么設(shè)計(jì)的。在functionName方法中也許進(jìn)行了大量的計(jì)算,開辟了很多線程,等待了很長的時間,但所有這些復(fù)雜的過程對于用戶(方法的使用者)來說都是不關(guān)心的,用戶關(guān)心的只有在hander中返回的“count”參數(shù)。

        這個方法可以被寫得更加漂亮,即添加一個Block類型變量,這其中用到C語言中的typedef。

        typedef void(blo)(int count);

        上例給帶有“count”參數(shù)的閉包起了一個blo的別名,所以在接下來的函數(shù)聲明中就可以使用blo來代替原本的參數(shù)類型,如下:

        -(void)functionName:(blo)hander;

        4 Block的截獲自動變量特性

        以以下代碼為例,

        此例中,blo();執(zhí)行時控制臺將輸出“I am Eric”,即便name代表的字符串在Block后已被修改成“I am Strong”。這就是Block對自動變量的截獲,簡單來說,Block對自動變量的截獲是指在編譯Block時,Block會保存(截獲)其中使用到的變量,不論Block中的變量的值在其后的語句中是否會被修改,Block中記錄的該變量的值永遠(yuǎn)不會改變。

        5 關(guān)于使用__block說明符

        Block對自動變量的截獲只能用于獲取變量的值,而不能對其進(jìn)行更改。當(dāng)嘗試去更改截獲的自動變量值的時候,編譯器將報錯。例如下面這種情況,

        此時,編譯器會報出以下錯誤:

        Variable is not assignable (missing __block type specifier)

        這個錯誤提示我們,若想在Block中修改截獲的自動變量的值,則需給變量加上“__Block”修飾符,如下所示,

        使用附有__Block說明符的自動變量可以在Block中賦值,該變量稱為__block變量。

        再舉一例,

        上例在Block中對arr變量進(jìn)行了初始化的賦值操作,執(zhí)行會發(fā)生錯誤,同樣需要給arr變量加__block修飾符來解決。

        但不是所有在Block中變更的對象都需要加上__Block說明符。如果在Block中僅對OC對象進(jìn)行操作,而不對其進(jìn)行賦值,這樣的變更就不會報錯,故無需加上__Block說明符。例如,

        此例截獲的變量是一個NSMutableArray類型的變量,Block中對一個可變數(shù)組進(jìn)行了操作,而沒有進(jìn)行賦值,所以可以正常執(zhí)行。

        用C語言指針來解釋以上情形,即未附有__Block說明符的自動變量不能在Block中更改變量指針的指向,但可以對變量進(jìn)行操作(改變地址內(nèi)容)。

        談到C語言指針,還要注意在Block中對C語言數(shù)組的使用方法。例如:

        執(zhí)行上面這段代碼,編譯器會發(fā)出以下錯誤:

        Cannot refer to declaration with an array type inside block

        Implicit conversion of an Objective-C pointer to ‘const char *’ is disallowed with ARC

        這是因?yàn)樵诂F(xiàn)在的Block中,截獲自動變量的方法沒有實(shí)現(xiàn)對C語言的截獲。對于這個問題,可以使用指針來解決,如下:

        6 Block存儲域

        存儲域一共分為三種:_NSConcreteStackBlock、_ NSConcreteGlobalBlock、_NSConcreteMallocBlock。即“棧存儲域”、“全局存儲域”、“堆存儲域”。Block與OC變量不同,它不全存儲在“棧存儲域”。

        a.Block存儲在“全局作用域”中的情況:

        如上所示,當(dāng)我們聲明一個全局的Block,Block就將被存儲在_NSConcreteGlobalBlock中。因?yàn)檫@種情況下在Block中無法對自動變量進(jìn)行截獲,即Block的內(nèi)容不依賴于運(yùn)行時的狀態(tài),因此將Block放在“全局作用域”中是最合適的。事實(shí)上,只要Block的內(nèi)容不依賴于運(yùn)行時的狀態(tài),也就是不對自動變量進(jìn)行截獲,那么不管Block的聲明實(shí)現(xiàn)位置在哪,這個Block都將被存儲在“全局作用域”當(dāng)中。

        b.Block存儲在“堆作用域”中的情況:

        當(dāng)將Block作為回調(diào)使用時,可以發(fā)現(xiàn)當(dāng)Block超出了塊作用域時仍可以被使用,例如在網(wǎng)絡(luò)回調(diào)中:

        我們經(jīng)常會使用類似上面這種方式進(jìn)行網(wǎng)絡(luò)數(shù)據(jù)請求,在Block中對請求返回?cái)?shù)據(jù)進(jìn)行處理。由于網(wǎng)絡(luò)請求是一個異步過程,所以在請求返回之后,已經(jīng)超出了Block的作用域。之所以這種情況下Block仍可以被使用,是因?yàn)檫@種情況下Block將被復(fù)制在“堆存儲域”中,包括Block中的自動變量也將會被拷貝到堆存儲域當(dāng)中。

        還有一種情況是當(dāng)將Block作為函數(shù)返回值返回時,Block同樣會被拷貝到“堆存儲域”中,再來進(jìn)行返回。

        大多數(shù)情況下,XCode(IDE)會自動幫編程者判斷Block在什么情況下需要被拷貝到“堆存儲域”中,但是在某些情況下編程者需要手動進(jìn)行這個過程,使用“copy”命令把Block從“棧”拷貝到“堆”中。

        7 Block循環(huán)作用域

        前文提到Block在引用自動變量時將把變量從棧中拷貝到堆中,所以,比如當(dāng)拷貝__strong屬性變量時,十分容易引起循環(huán)引用,進(jìn)而造成內(nèi)存泄漏。下面這段代碼就會引起循環(huán)引用:

        其中ViewController持有一個變量Block,但在Block中再次截獲了self,也就是Block持有self,ViewController的釋放需要Block來釋放self,而Block同樣需要ViewController釋放才會釋放,這是標(biāo)準(zhǔn)的循環(huán)引用。解決這個問題可以使用__weak說明符,如下:

        當(dāng)使用__weak說明符后,Block不再持有self,于是打破了循環(huán)引用。

        事實(shí)上并不是在Block中顯示的出現(xiàn)self以后才會發(fā)生循環(huán)引用,下面這種情況也會發(fā)生循環(huán)引用:

        上例Block中沒有出現(xiàn)self,但在這種情況下也會發(fā)生循環(huán)引用。原因是這種情況雖然沒有使用get方法來獲取變量,但是直接通過內(nèi)存地址獲取了變量,等同于以下代碼:

        這解釋了為什么第二種情況也會發(fā)生循環(huán)應(yīng)用。解決這樣的循環(huán)引用,同樣可以使用__weak說明符:

        需要注意的是,如果一個Block在運(yùn)行時沒有被調(diào)用,但是在Block中發(fā)生了循環(huán)引用,就也會發(fā)生內(nèi)存泄漏。原因是Block將自動變量拷貝到“堆存儲域”的動作是在編譯時期完成的,所以即便沒有調(diào)用Block,XCode也已經(jīng)在編譯時期將自動變量拷貝到了“堆存儲域”當(dāng)中。

        解決Block的循環(huán)引用問題的方法除以上所述使用__weak說明符外,還有另外一種方式。為了解決循環(huán)引用我們必須打破雙方其中一方的引用,所以上例中使用了__weak說明符,但下面的代碼也可以達(dá)到相同的目的:

        以上代碼中聲明了一個名為myObject的類,這個類中的Block發(fā)生了循環(huán)引用,如果聲明了這個類的一個實(shí)列對象,那么這么對象因?yàn)檠h(huán)引用而不會被釋放。

        如上,當(dāng)聲明一個Object的myObject類后,Object就已經(jīng)發(fā)生了內(nèi)存泄漏,但是如果在合適的位置來釋放Block就可以解決這個問題:

        如上,當(dāng)將Block置空以后,block就失去了對Object的引用,所以這種情況不會再發(fā)生循環(huán)引用。但這樣直接將Block置空的方式是十分危險的,因?yàn)楦淖兞薆lock初始化的值,后面的代碼運(yùn)行結(jié)果就可能不同于所預(yù)料的了。所以選擇置空Block的時刻非常關(guān)鍵。

        8 總結(jié)

        本文從Block的語法,Block作為函數(shù)參數(shù)使用的方法,Block對自動變量的截獲,Block的使用方式:__Block說明符、存儲域這些方面全面介紹了Block,并針對因循環(huán)引用導(dǎo)致內(nèi)存泄漏的問題提出了解決辦法。通過本文幫助讀者深入認(rèn)識Block并更好地理解Block。

        [1] Kazuki Sakamoto,Tomohiko Furumoto.Objective-C 高級編程.人民郵電出版社,2013-06-01

        本項(xiàng)目由北京信息科技大學(xué)2016年人才培養(yǎng)質(zhì)量提高經(jīng)費(fèi)(5111610800)支持。

        猜你喜歡
        聲明自動變量
        本刊聲明
        本刊聲明
        中國德育(2022年12期)2022-08-22 06:16:46
        抓住不變量解題
        也談分離變量
        自動捕盜機(jī)
        本刊聲明
        本刊聲明
        基于STM32的自動喂養(yǎng)機(jī)控制系統(tǒng)
        電子測試(2018年10期)2018-06-26 05:53:36
        關(guān)于自動駕駛
        汽車博覽(2016年9期)2016-10-18 13:05:41
        SL(3,3n)和SU(3,3n)的第一Cartan不變量
        免费无码黄网站在线观看| 热久久美女精品天天吊色| 亚洲一区二区三区日韩在线观看| 麻豆亚洲一区| 无码人妻av免费一区二区三区| 国产熟人av一二三区| 在线永久看片免费的视频| 欧美日韩中文字幕日韩欧美| 美女福利视频在线观看网址| 欧美巨鞭大战丰满少妇| 国产av无码专区亚洲av极速版| 日韩一区二区肥| 99久久这里只精品国产免费| 日本不卡的一区二区三区| 人妻少妇精品视频一区二区三区l 日韩人妻中文字幕专区 | 99精品人妻少妇一区二区三区| 十四以下岁毛片带血a级| 青青久在线视频免费观看| 亚洲精品中文字幕观看| 亚洲精品国产成人久久av盗摄| 风流老太婆大bbwbbwhd视频| 亚洲欧美精品suv| 亚洲专区欧美| 亚洲天堂色婷婷一区二区| av素人中文字幕在线观看| 3d动漫精品啪啪一区二区免费| 久久夜色精品国产噜噜亚洲av| 激情久久无码天堂| 国产又湿又爽又猛的视频| 国产成人无码a在线观看不卡| 国产成人av 综合 亚洲| 亚洲aⅴ无码国精品中文字慕| 亚洲AV无码日韩一区二区乱| 中国男男女在线免费av| 久久www免费人成—看片| 传媒在线无码| 隔壁人妻欲求不满中文字幕| 日本一区二区三区视频免费观看| 日本入室强伦姧bd在线观看 | 2017天天爽夜夜爽精品视频| 亚洲av高清不卡免费在线|