ios 知識點總結(十一)之RUNLOOP

####1.iOS系統中,提供了兩種Runloop:NSrunloop和CFRunLoopRef;

  • CGRunLoopRe是在CoreFoundation框架內的,提供純C函數的API,所有的API都是線程安全的。
  • NSRunloop是基於CFRunloopref的封裝,提供了面向對象的API,但是這些API不是線程安全的。

###2.使用場景

  • 不開啓runloop:在處理耗時的操作時,一般都會開闢一個子線程,操作完成之後,子線程線性的執行代碼然後退出,此時是不開啓runloop的。
  • 開啓runloop:
    1)當創建一個全局線程時,當開始之後,並子線程線性執行完成之後就處於死亡狀態,不能再重新開啓。
    2)Event Loop模式:線程的任務直到我們主動讓線程退出爲止永遠不會結束,可以在需要的時候讓線程做對應的事情。
    3)RunLoop能正常運行的條件:至少要包含一個Mode,並且該Mode下需要至少一個事件源(Timer/Source),而且要運行在有事件源的mode下,但是經過NSRunLoop封裝之後,只可以往mode中添加兩類事件:NSPort和NSTimer。
    4)RunLoop是寄生於線程的纖細循環機制,它能保證線程存活,而不是線性執行完任務就消亡。
    5)Runloop與線程是一一對應的,每個線程只有唯一與之對應的一個Runloop,只能在當前線程中獲取線程對應的RunLoop,但是主線程除外。
    6)子線程默認沒有RunLoop,需要我們去主動開啓。
    7)RunLoop有三種啓動方式run、runUntilDate:(NSDate *)limitDate、runMode:(NSString *)mode beforeDate:(NSDate *)limitDate。第一種無條件永遠運行RunLoop並且無法停止,線程永遠存在。第二種會在時間到後退出RunLoop,同樣無法主動停止RunLoop。前兩種都是在NSDefaultRunLoopMode模式下運行。第三種可以選定運行模式,並且在時間到後或者觸發了非Timer的事件後退出。
  • 讓線程定時執行任務
    NSTimer並不是嚴格的按照設定的時間點來觸發的,一般會會在runloop循環一次時執行(但還是會根據當前任務執行的時間長短來決定50-100ms),但是NSTimer提供了一個toerance屬性來設置寬容忍度,可以是NSTimer儘可能的答道精準。
  • scrollView滑動對NStimer的影響
    偶爾我們會發現,NStimer在我們滑動ScrolleView的時候,NStimer會停止不起作用,這是因爲:
    1)在runloop起作用時,runloop每次只能執行在一個mode下,主要是讓不同的mode中的Item互不影響。
    2)Nstimer默認是在NSDefaultRunLoopMode中,一般其情況下主線程就是在NSDefaultRunLoopMode下,所有NSTimer可以正常運行。
    3)但是當滑動ScroolView時,主線程的runloop自動切換到了UITrackingRunLoopMode,所以現在的runloop需要處理該mode下的item,但是NStimer並不在該Mode下,runloop就不會處理NStimer了。
    4)當ScrollerView滑動結束之後,Runloop自動切換到NSDefaultRunLoopMode,這時NSTimer就又正常運行了。
    5)所以如果想讓NStimer正常運行,我們需要把Item(timer/source)同時加入多個Mode(NSRunLoopCommonModes),這樣不管runloop處於什麼mode下,item都是當前Mode的item,都會得到處理。
  • NStimer導致Viewcontroller無法釋放
    原因:爲了確保Nstimer正常運轉,當Nstimer加入到Runloop以後系統會對NStimer執行一次retain,一般情況下我們設置NSTimer時都會設置Target爲Self,這時Nstimer會對Controller有一個強引用,這時會導致兩者互相持有而無法釋放。
    解決方法:
    1)把NStimer封裝到另一個Target中,控制器通過這個target間接使用NStimer。
    2)另一種方式時直接增加NSTimer的擴展(分類),讓NSTImer自身作爲Target,同時可以將操作封裝在Block中,例如:NSTimer+Block
    3)所以一般在使用Timer時需要與invaildate成對出現,不管時重複執行還是在單次執行都要在結束時執行incaildate,只是在單次執行完成之後會自動調用invaildate方法。
  • Runloop釋放的問題
    1.在主線程中
    1)當runloop開啓時,會自動創建一個自動緩存池。
    2)當Runloop在休息之前會釋放掉自動緩存池的東西。
    3)然後重新創建一個信的空的自動緩存池
    4)當Runloop被喚醒又開始重新跑圈時,Timer,source等新時間就會放到新的自動緩存池中,後面就重複2-4的操作。
    2.Nsthread和NSOperationQueue開闢子線程需要手動創建autoreasepool,GCD開闢子線程不需要手動創建,因爲GCD的每個隊列都會自動創建autoreleasepool。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章