RunLoop
本來一個線程只能跃脊,處理一個任務(wù)流就退出淮野,執(zhí)行完成該任務(wù)流就退出銷往捧书。單我們希望,線程能隨時處理問題而不退出骤星。模型基本如下
func loop(){
do{
var message = getMessage()
handleMessage(message)
}while(message != quilt)
}
該模型線程一直在跑经瓷,我們希望,當(dāng)沒有任務(wù)要處理的時候洞难,線程就休眠舆吮,那么RunLoop就應(yīng)運(yùn)而生了
iOS中有2套關(guān)于RunLoop的API:
1.NSRunLoop 線程不安全
2.CFRunLoopRef 線程安全
RunLoop And NSThread
RunLoop和線程是一一對應(yīng)的關(guān)系,一個線程有且只有一個RunLoop,而且還是默認(rèn)沒有開啟的(主線程的RunLoop是默認(rèn)開啟的)
NSRunLoop.currentRunLoop()
NSRunLoop.mainRunLoop()
2套api
CFRunLoopGetCurrent()
CFRunLoopGetMain()
RunLoopMode
系統(tǒng)默認(rèn)注冊了5個model色冀,暫時只有這3個有點(diǎn)意義
- NSDefaultRunLoopMode:App的默認(rèn)Mode潭袱,通常主線程是在這個Mode下運(yùn)行
- UITrackingRunLoopMode:界面跟蹤 Mode,用于 ScrollView 追蹤觸摸滑動(滑動的時候锋恬,主線程的RunLoop在這個模式下運(yùn)行)屯换,保證界面滑動時不受其他 Mode 影響
- NSRunLoopCommonModes: 這是一個占位用的Mode,不是一種真正的Mode(包含上面2個model的情況)
RunLoop 和 NSTimer
1.mainThread主線程
let myT = NSTimer(timeInterval: 3, target: self, selector: Selector("circleAction"), userInfo: nil, repeats: true)
NSRunLoop.currentRunLoop().addTimer(myT, forMode: NSDefaultRunLoopMode)//這個模式下會在普通模式下運(yùn)行与学,滑動scrollView的時候?qū)⒉荒苡|發(fā)定時器
NSRunLoop.currentRunLoop().addTimer(myT, forMode: UITrackingRunLoopMode)//只有在滑動scrollview的時候觸發(fā)
//NSRunLoopCommonModes滑動和不滑動都能觸發(fā)這個定時器
2.otherThread其他線程
let t = NSTimer(timeInterval: 2, target: self, selector: Selector("circleAction"), userInfo: nil, repeats: true)
let r = NSRunLoop.currentRunLoop()
r.addTimer(t, forMode: NSRunLoopCommonModes)//其他線程N(yùn)SRunLoopCommonModes和NSDefaultRunLoopMode才會執(zhí)行
r.run()//啟動其他線程的RunLoop
RunLoop 和 Observer
觀察該RunLoop的狀態(tài)
// 1.創(chuàng)建Observer
// 第一個參數(shù):用于分配該observer對象的內(nèi)存
// 第二個參數(shù):用以設(shè)置該observer所要關(guān)注的的事件
// 第三個參數(shù):用于標(biāo)識該observer是在第一次進(jìn)入run loop時執(zhí)行, 還是每次進(jìn)入run loop處理時均執(zhí)行
// 第四個參數(shù):用于設(shè)置該observer的優(yōu)先級
// 第五個參數(shù): observer監(jiān)聽到事件時的回調(diào)block
let observe = CFRunLoopObserverCreateWithHandler(kCFAllocatorDefault, CFRunLoopActivity.AllActivities.rawValue, true, 0) { (o: CFRunLoopObserver!, a:CFRunLoopActivity) -> Void in
switch a {
case CFRunLoopActivity.Entry:
print("RunLoop Entry")
case CFRunLoopActivity.BeforeTimers:
print("RunLoop BeforeTimers")
case CFRunLoopActivity.BeforeSources:
print("RunLoop BeforeSources")
case CFRunLoopActivity.BeforeWaiting:
print("RunLoop BeforeWaiting")
case CFRunLoopActivity.AfterWaiting:
print("RunLoop 等待后")
case CFRunLoopActivity.Exit:
print("RunLoop 退出")//切換model的時候會退出彤悔,再進(jìn)入
default:
print("---------------------:\(a)")
break;
}
}
// 2.添加監(jiān)聽
/*
第一個參數(shù): 給哪個RunLoop添加監(jiān)聽
第二個參數(shù): 需要添加的Observer對象
第三個參數(shù): 在哪種模式下監(jiān)聽
*/
CFRunLoopAddObserver(CFRunLoopGetMain(), observe, kCFRunLoopDefaultMode);
//滑動UIScrollview的時候輸出:
RunLoop BeforeTimers
RunLoop BeforeSources
RunLoop BeforeWaiting
RunLoop 等待后
RunLoop BeforeTimers
RunLoop BeforeSources
RunLoop 退出 //滑動先退出原來的model,在進(jìn)入下一個model癣防,切換model
RunLoop Entry
RunLoop BeforeTimers
RunLoop BeforeSources
RunLoop BeforeWaiting
應(yīng)用場景:AsyncDisplayKit,在后臺線程維護(hù)一套和UI組件相同的屬性蜗巧,在合適的時機(jī)(監(jiān)聽主線程的RunLoop,當(dāng)RunLoop進(jìn)入BeforeWaiting的時候進(jìn)行UI刷新)在主線程上蕾盯,把維護(hù)的屬性和UI自有屬性同步。
RunLoop 和 NSMachPort
應(yīng)用場景,后臺開辟一個線程蓝丙,來監(jiān)聽一個port级遭。通常情況下,調(diào)用者需要持有這個 NSMachPort (mach_port) 并在外部線程通過這個 port 發(fā)送消息到 loop 內(nèi)
let r = NSRunLoop.currentRunLoop()
let markPort = NSMachPort(machPort: 22)
r.addPort(markPort, forMode: NSRunLoopCommonModes)
r.run()