小碼哥iOS學習筆記第十七天: Runloop線程保活

1、線程失活

  • 新建OC工程, 定義BWThread繼承自NSThread, 重寫-dealloc方法以下圖

  • Main.storyboard中結構以下

  • ViewController中代碼以下

  • 運行程序, pushViewController中, 有以下打印

  • 當建立的子線程執行完block後, 會當即釋放掉

2、Runloop線程保活

  • 每一條線程都有與之相對應的惟一一個RunLoop, 只有在主動獲取RunLoop時纔會建立(主線程中的RunLoop由系統自動建立)
  • 咱們能夠經過在線程中使用RunLoop來對線程保活
  • 固然, 咱們在使用RunLoop對線程進行保活的時候, 不能僅僅運行就好了, 由於RunLoop當前執行的_currentModel中若是沒有Sources0, Sources1, Timers, Observers, 那麼RunLoop會自動退出

  • 因此咱們須要建立一個事件讓RunLoop處理, 這樣RunLoop纔不會退出
  • 運行程序, thread留在了內存中, 沒有被釋放

  • 咱們能夠引用thread, 而後在touchesBegan:withEvent:方法中,給子線程添加事件

  • 運行後點擊屏幕, 能夠看到thread保持活性, 依然在能夠事件

  • 若是去掉RunLoop, 能夠看到,不論怎麼點擊屏幕, 都不會再有事件, 此時thread就會失活, 因此就算被ViewController強引用, 依然沒法保持thread的活性

3、釋放RunLoop保活的線程

  • ViewController重寫-dealloc方法, 能夠發現當ViewController退出被銷燬時, thread依然留在了內存中, 沒有被釋放, 說明thread發生了內存泄漏

  • 咱們能夠經過中止RunLoop的運行, 來釋放threadoop

  • ViewController上添加一個按鈕, 咱們要在點擊釋放按鈕時, 將RunLoop中止線程

  • ViewController中代碼以下, 當點擊釋放按鈕時, 在thread中中止RunLoop

  • 運行程序, 點擊釋放按鈕, 能夠發現RunLoop並無被中止, 點擊屏幕依然觸發事件

  • 咱們能夠查看RunLoop-run方法的介紹

  • 能夠看到-run方法裏面, 其實是一個死循環, 在不停的調用-runMode:beforeDate:方法
  • 而咱們經過CFRunLoopStop(CFRunLoopGetCurrent())釋放掉的, 只不過是其中某一次循環中的-runMode:beforeDate:而已
  • 因此咱們在調用RunLoop的時候, 須要使用-runMode:beforeDate:方法, 而不是-run方法

  • 運行程序, 能夠看到, 當點擊屏幕後, thread在執行一次事件以後就會失活, 因此咱們須要對-runMode:beforeDate:進行循環處理

  • 再次運行程序, 能夠看到點擊屏幕後能夠連續的響應事件, 只不過釋放以後RunLoop依然在工做

  • 這是由於-runMode:beforeDate:被中止後, 經過循環又進行了一次-runMode:beforeDate:3d

  • 因此, 咱們須要使用一個標識來控制是否循環-runMode:beforeDate:code

  • 再次運行程序, 就能夠控制thread的存活了

  • ViewController銷燬, 能夠看到thread也銷燬了

設置thread隨着ViewController釋放一塊兒釋放

  • 運行程序, 進入ViewController後直接退出, 能夠發現ViewController被釋放了, 而thread並無釋放

  • -dealloc中執行-freeThread:方法, 執行程序

  • 根據打印的信息, 能夠看到執行了stop方法後, thread依然沒有被釋放
  • 這主要是由於, 在ViewController-dealloc方法執行時,ViewController已經處於被釋放的狀態, 當須要執行到stop時, ViewController已經被釋放
  • 因此, 咱們須要設置當thread的任務-stop執行完以後, 在執行後面的代碼

  • 接着咱們執行程序, 能夠發現, -stop執行完以後才執行的-dealloc, 說明-stop執行完以後, ViewController才被釋放
  • 只是此時thread依然沒有被釋放

  • 這是由於, 等到RunLoop被中止, 再次進入while循環判斷的時候ViewController已經被釋放, 此時的weakSelf的值爲nil, 因此!weakSelf.isStop的值爲YES, 再次進入了循環, 啓動了RunLoop

  • 因此, 在開啓RunLoop的循環條件中, 加入weakSelf必須有值的條件語句

  • 這樣, 就能夠在ViewController退出時, thread也跟着正常釋放

解決: 點擊釋放後退出ViewController時崩潰的問題

  • 當進入ViewController後, 先點擊釋放按鈕, 使thread失活後再次popViewController, 就會發生運行時錯誤

  • 這主要是由於waitUntilDone設置爲YES, 程序會等thread執行完以後再執行後面的代碼, 此時thread已經失活, 因此纔會出現運行時錯誤
  • 咱們能夠再中止thread以後, 將self.thread置空, 再加入下面的判斷, 就可保證程序的正常運行

  • 運行程序, 進入ViewController後, 先點擊釋放按鈕, 使thread失活後再次popViewController, 能夠看到程序正常運行

  • 其中ViewControllerthread也都被釋放了
相關文章
相關標籤/搜索