iOS - RunLoop - 胡诌

RunLoop

本来一个线程只能,处理一个任务流就退出,执行完成该任务流就退出销往。单我们希望,线程能随时处理问题而不退出。模型基本如下

func loop(){
    do{
        var message = getMessage()
        handleMessage(message)
    }while(message != quilt)
}

该模型线程一直在跑,我们希望,当没有任务要处理的时候,线程就休眠,那么RunLoop就应运而生了

iOS中有2套关于RunLoop的API:

1.NSRunLoop 线程不安全
2.CFRunLoopRef 线程安全

RunLoop And NSThread

RunLoop和线程是一一对应的关系,一个线程有且只有一个RunLoop,而且还是默认没有开启的(主线程的RunLoop是默认开启的)

 NSRunLoop.currentRunLoop()
 NSRunLoop.mainRunLoop()
2套api
 CFRunLoopGetCurrent()
 CFRunLoopGetMain()

RunLoopMode

系统默认注册了5个model,暂时只有这3个有点意义

  • NSDefaultRunLoopMode:App的默认Mode,通常主线程是在这个Mode下运行
  • UITrackingRunLoopMode:界面跟踪 Mode,用于 ScrollView 追踪触摸滑动(滑动的时候,主线程的RunLoop在这个模式下运行),保证界面滑动时不受其他 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)//这个模式下会在普通模式下运行,滑动scrollView的时候将不能触发定时器
NSRunLoop.currentRunLoop().addTimer(myT, forMode: UITrackingRunLoopMode)//只有在滑动scrollview的时候触发
//NSRunLoopCommonModes滑动和不滑动都能触发这个定时器

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)//其他线程NSRunLoopCommonModes和NSDefaultRunLoopMode才会执行
 r.run()//启动其他线程的RunLoop

RunLoop 和 Observer

观察该RunLoop的状态

        // 1.创建Observer
        // 第一个参数:用于分配该observer对象的内存
        // 第二个参数:用以设置该observer所要关注的的事件
        // 第三个参数:用于标识该observer是在第一次进入run loop时执行, 还是每次进入run loop处理时均执行
        // 第四个参数:用于设置该observer的优先级
        // 第五个参数: observer监听到事件时的回调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的时候会退出,再进入
            default:
                print("---------------------:\(a)")
                break;
            }
        }
        // 2.添加监听
        /*
        第一个参数: 给哪个RunLoop添加监听
        第二个参数: 需要添加的Observer对象
        第三个参数: 在哪种模式下监听
        */
        CFRunLoopAddObserver(CFRunLoopGetMain(), observe, kCFRunLoopDefaultMode);
//滑动UIScrollview的时候输出:
RunLoop BeforeTimers
RunLoop BeforeSources
RunLoop BeforeWaiting
RunLoop 等待后
RunLoop BeforeTimers
RunLoop BeforeSources
RunLoop 退出 //滑动先退出原来的model,在进入下一个model,切换model
RunLoop Entry
RunLoop BeforeTimers
RunLoop BeforeSources
RunLoop BeforeWaiting

应用场景:AsyncDisplayKit,在后台线程维护一套和UI组件相同的属性,在合适的时机(监听主线程的RunLoop,当RunLoop进入BeforeWaiting的时候进行UI刷新)在主线程上,把维护的属性和UI自有属性同步。

RunLoop 和 NSMachPort

应用场景,后台开辟一个线程,来监听一个port。通常情况下,调用者需要持有这个 NSMachPort (mach_port) 并在外部线程通过这个 port 发送消息到 loop 内

 let r = NSRunLoop.currentRunLoop()
 let markPort = NSMachPort(machPort: 22)
 r.addPort(markPort, forMode: NSRunLoopCommonModes)
 r.run()

案例

你可能感兴趣的:(iOS - RunLoop - 胡诌)