iOS之輕鬆上手block,iosblock

來源:互聯網
上載者:User

iOS之輕鬆上手block,iosblock

原文出處: codingZero   歡迎分享原創到伯樂頭條

導語

不會使用block的iOS程式員,不是一個合格的程式員
學會了block,你再也不想用繁瑣的代理
block沒有你想象中的那麼難,不要害怕,不要畏懼,勇敢嘗試
筆者入行iOS時已經是ARC的天下,所以這裡只說ARC環境下的使用

什麼是block

block其實就是一個代碼塊,把你想要執行的代碼封裝在這個代碼塊裡,等到需要的時候再去調用。那block是OC對象嗎?答案是肯定的

 

 

來自官方文檔

筆者以英語3.9級的水平給大家翻譯下,“block是一個OC對象,這意味著它能被添加到集合,比如NSArray、NSDictionary”

block的定義block的賦值

格式:block = ^傳回值類型(參數列表){}

任務需求:點擊A控制器右上方“建立”按鈕跳到B控制器,B控制器新增連絡人...後,點擊“儲存”按鈕返回A控制器,並將新添加的連絡人展示到列表中

問題來了,如何將B控制器中的資料傳遞給A控制器呢?

那還不簡單,A控制器直接把連絡人數組傳遞給B控制器,B控制器建立連絡人後添加到數組中,然後返回A控制器,在A控制器的viewWillAppear方法中重新整理表格就OK了。

方法可行,但是不得不說,相當low,B控制器是用來新增連絡人...的,至於連絡人數組什麼情況,無需關心,所以,不要把數組傳遞給B控制器

B控制器要做的僅僅只是,建立連絡人,然後把連絡人對象傳遞給A控制器,至於A控制器拿到連絡人後會做什麼,那是A的事情,與B無關

看到這裡,很多人可能已經想到了代理,沒錯,代理也可以實現,但…是…,B控制器定義協議,聲明代理方法,A控制器設定代理,遵守協議,然後實現代理方法,B控制器在合適的地方調用代理方法,臥槽,好麻煩有木有,筆者都不想寫代碼了,還是回家種田去吧

好了不廢話了,進入正題

使用block傳遞資料block常見雷區—循環參考

使用block有一個特別要注意的地方,循環參考,何為循環參考?你引用我,我引用你,誰也不釋放誰,對象無法銷毀,佔用記憶體

我們來看一個循環參考的一個例子

 

 

 

注意看控制台輸出,當點擊“取消”時,B控制器被銷毀,dealloc方法被調用

把注釋掉的代碼開啟,再運行

 

 

 

點擊“取消”按鈕,B被移除,但是dealloc方法沒有調用,所以說,B控制器並沒有銷毀,why?

block對象賦值給了B控制器的屬性,因此B會對block有一個強引用,而block中又用到了self(B控制器對象),block會對使用到的外部變數進行捕獲,所以,block對B控制器也有一個強引用,最終造成循環參考,誰也無法釋放

循環參考解決方案

循環參考如何解決?很簡單,一行代碼搞定

 

 

 

使用weakSelf(名稱隨便取的)替代self,block將不再對self進行強引用
圖中__weak也可使用__unsafe_unretained,區別就是__weak修飾的指標,當對象銷毀後,指標會被自動置為nil,而__unsafe_unretained修飾的指標,當對象銷毀後會變成野指標,為了安全,推薦使用__weak

 block的分類
block可分為三種
 
  • NSStackBlock:棧block
  • NSMallocBlock:堆block
  • NSGlobalBlock:全域block
1. 棧block

特點:生命週期由系統控制,函數返回即銷毀
用到局部變數、成員屬性變數,且沒有強指標引用的block都是棧block

a.用到局部變數(圖1),i為局部變數,block直接在NSLog中列印,沒有被指標引用

 

 

圖1

b.用到成員屬性變數(圖2),name為成員屬性

 

 

圖22. 堆block

特點:沒有強指標引用即銷毀,生命週期由程式員手動管理
棧block如果有強指標引用或copy修飾的成員屬性引用就會被拷貝到堆中,變成堆block

a.強指標引用(圖3),block被testBlock引用,testBlock就是一個block類型的強指標(ARC環境下預設就是強指標)

 

 

圖3

b.copy修飾的成員屬性引用(圖4)

 

 

圖43. 全域block

特點:命長,有多長?很長很長,人在塔在(應用程式在它就在)
沒有用到外界變數,或者只用到全域變數、靜態(static)變數的block就是全域block

對於全域block,有沒有指標引用都不影響,block類型的成員屬性無論是用assign、weak、strong還是copy修飾都無所謂,不過開發中很少用到全域block,所以不要用weak或assign

a.沒有用到外界變數(圖5),中block沒有用到外界變數,所以就算用weak修飾也是全域block(舉個例子而已,開發中不要用weak,用了也別說是筆者教的)

 

 

圖5

b.只用到全域變數、靜態(static)變數(圖6),str為全域變數,str1為靜態變數,只用到其中一個也是全域block

 

 

圖6

分類總結
1.沒有用到外界變數或只用到全域變數、靜態變數的block為全域block,生命週期從建立到應用程式結束
2.用到局部變數、成員屬性變數的block為棧block,生命週期系統控制,函數返回即銷毀
3.有強指標引用或copy修飾的成員屬性引用的block會被複製一份到堆中成為堆block,沒有強指標引用即銷毀,生命週期由程式員控制

block對外界變數的捕獲

a.基礎資料型別 (Elementary Data Type)—局部變數
block會拷貝該變數的值當做常量使用,外界修改變數的值不會影響block內部,且block內部不能對其修改

block內部修改外界變數i的值直接報錯,如果想要修改,可以在int i = 0前面加上關鍵字__block,此時i等效於全域變數或靜態變數

 

 

 

外界變數i從0變成了1,block內部列印依然是0

 

 

 

b.基礎資料型別 (Elementary Data Type)—靜態變數、全域變數、成員屬性變數
block直接存取變數地址,在block內部可以修改變數的值,並且外部變數被修改後,block內部也會跟著變

圖中_k為成員屬性變數,初始值i = 10,j = 20,k = 0,block內部只對i、j、k進行一次自增操作,列印結果卻是i = 12,j = 22,k = 2,所以外部的自增操作也影響了內部,即訪問的是同一個記憶體位址

 

 

 

c.指標類型—局部變數
block會複製一份指標並強引用指標所指對象,且內部不能修改指標的指向

圖中被注釋掉的代碼試圖修改指標指向,所以會報錯(如果想要修改,在前面加上__block),但是可以修改所指對象的值,如str從“abc”變成了“abcdef”

 

 

 

d.指標類型—全域變數、靜態變數、成員變數屬性
block不會複製指標,但是會強引用該對象,內部可修改指標指向,block會強引用成員屬性變數所屬的對象,這也是為什麼block屬性內部用到self.xxx會引起循環參考的原因

圖中str2為成員屬性,由於NSString是不可變的,所以從列印結果可以看出,在block內部修改了外界指標變數的引用,指向了新的字串

 

 

 講到這裡,筆者對block的理解已全部分享給大家,並隨時歡迎各位讀者的補充與糾正

問啊-定製化IT教育平台,牛人一對一服務,有問必答,開發編程社交頭條 官方網站:www.wenaaa.com

QQ群290551701 聚集很多互連網精英,技術總監,架構師,專案經理!開源技術研究,歡迎業內人士,大牛及新手有志於從事IT行業人員進入!

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.