美文网首页
RunLoop 的坑

RunLoop 的坑

作者: 幸运者_Lucky | 来源:发表于2019-07-26 18:01 被阅读0次

由于项目中, 使用 runLoop.run()方法, 当执行 remove portCFRunLoopStop(CFRunLoopGetCurrent()), RunLoop一直没有退出, 造成开启RunLoop 之后的代码一直没有执行, 查阅了苹果 API 说明, 总结了下面的问题。

文中包含大量的 API 说明,如果只关心结果,请直接参考中文文字。

RunLoop.run()

If no input sources or timers are attached to the run loop, this method exits immediately;
otherwise, it runs the receiver in the NSDefaultRunLoopMode by repeatedly invoking run(mode:before:). In other words, this method effectively begins an infinite loop that processes data from the run loop’s input sources and timers.

Manually removing all known input sources and timers from the run loop is not a guarantee that the run loop will exit. macOS can install and remove additional input sources as needed to process requests targeted at the receiver’s thread. Those sources could therefore prevent the run loop from exiting.

RunLoop.run(until:)

If no input sources or timers are attached to the run loop, this method exits immediately; otherwise, it runs the receiver in the NSDefaultRunLoopMode by repeatedly invoking run(mode:before:) until the specified expiration date.

Manually removing all known input sources and timers from the run loop is not a guarantee that the run loop will exit. macOS can install and remove additional input sources as needed to process requests targeted at the receiver’s thread. Those sources could therefore prevent the run loop from exiting.

RunLoop.run(mode:before:)

If no input sources or timers are attached to the run loop, this method exits immediately and returns false; otherwise, it returns after either the first input source is processed or limitDate is reached. Manually removing all known input sources and timers from the run loop does not guarantee that the run loop will exit immediately. macOS may install and remove additional input sources as needed to process requests targeted at the receiver’s thread. Those sources could therefore prevent the run loop from exiting.

Manually removing all known input sources and timers from the run loop does not guarantee that the run loop will exit immediately.

swift RunLooprun(), run(until:), run(mode:before:)
这三个方法, 即使 remove 所有 sources, timers , 也不会立刻 exit
但经过测试 run(mode:before:) 在调用 remove(port:, forMode:) 或者 调用CFRunLoopStop(CFRunLoopGetCurrent()) 会退出, 但文档很隐晦的加了 immediately, 所以也很不确定在调用CFRunLoopStop(CFRunLoopGetCurrent()) 之后是否会立即退出。

CFRunLoopRun()

The current thread’s run loop runs in the default mode (see Default Run Loop Mode) until the run loop is stopped with CFRunLoopStop(_:) or all the sources and timers are removed from the default run loop mode.

Run loops can be run recursively. You can call CFRunLoopRun() from within any run loop callout and create nested run loop activations on the current thread’s call stack.

CFRunLoopRunInMode(_ : _ : _ :)

The run loop exits with the following return values under the indicated conditions:

  • kCFRunLoopRunFinished. The run loop mode mode has no sources or timers.
  • kCFRunLoopRunStopped. The run loop was stopped with CFRunLoopStop(_:).
  • kCFRunLoopRunTimedOut. The time interval seconds passed.
  • kCFRunLoopRunHandledSource. A source was processed. This exit condition only applies when returnAfterSourceHandled is true.

You must not specify the commonModes constant for the mode parameter. Run loops always run in a specific mode. You specify the common modes only when configuring a run-loop observer and only in situations where you want that observer to run in more than one mode.

CFRunLoopStop(_:)

This function forces rl to stop running and return control to the function that called CFRunLoopRun() or CFRunLoopRunInMode(_:_:_:) for the current run loop activation. If the run loop is nested with a callout from one activation starting another activation running, only the innermost activation is exited.

看过 CFRunLoop 的介绍, 决定以后使用 CFRunLoop, 经过测试, 使用 CFRunLoopRun()CFRunLoopRunInMode(_ : _ : _ :) run 的 RunLoop , 可以使用CFRunLoopStop(_:)立即 退出。面对 swift RunLoop 的不确定性, CFRunLoop API 更稳定。

下面简单说明一下 RunLoop 的实际应用:

  1. 可以使用 perform(_ aSelector: Selector, with anArgument: Any?, afterDelay delay: TimeInterval, inModes modes: [RunLoop.Mode]), 来延迟加载图片等, mode 设置为 default.
  2. 不退出的 thread , 在 threadRunLoop 中加入一个 port, 开启 RunLoop, 防止退出。
  3. 执行一系列任务之后,RunLoop 退出时, 处理问题。
    我的问题就发生在这里,当 remove port 和走 CFRunLoopStop(CFRunLoopGetCurrent()) 的时候, RunLoop 都没有退出。因为我用的是 RunLoop.current.run(),具体细节参考上面。

事例代码如下:

class ViewController: UIViewController {
    lazy var thread: Thread = {
        return Thread.init(target: self, selector: #selector(run), object: nil)
    }()
    let port = Port.init()
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
        thread.start()
    }

    @objc func run() {
        print("run: ", Thread.current)
        RunLoop.current.add(port, forMode: .default)
        print("ran: ", Thread.current)
    }
    
    @objc func run1() {
        print("run1: ", Thread.current)
        CFRunLoopStop(CFRunLoopGetCurrent())
    }
    
    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        perform(#selector(run1), on: thread, with: nil, waitUntilDone: false)
    }
}

RunLoop 具体介绍参考: 《深入理解RunLoop

相关文章

  • RunLoop 的坑

    由于项目中, 使用 runLoop.run()方法, 当执行 remove port 和CFRunLoopStop...

  • RunLoop 填坑

    之前关于RunLoop只知道一点,最近花时间重新系统的学习了一下,以下是我的学习笔记及总结。有不足的部分,望大佬不...

  • iOS Runloop 线程保活及坑

    iOS Runloop 线程保活及坑 上面的代码, Thread 这个类继承自 NSThread ,然后重写了 d...

  • 2019 iOS面试题-----RunLoop数据结构、RunL

    RunLoop概念 RunLoop的数据结构 RunLoop的Mode RunLoop的实现机制 RunLoop与...

  • RunLoop

    RunLoop简单概述 RunLoop相关类 RunLoop逻辑处理 RunLoop实践 RunLoop简单概述 ...

  • Runloop分析

    RunLoop 参考:深入理解RunLoop ibireme:《深入理解RunLoop》 Runloop 的概念 ...

  • 2019 -----RunLoop数据结构、RunLoop的实现

    runloop 概念 runloop 数据结构 runloop的 Mode runloop 的实现机制 runlo...

  • iOS之RunLoop详解与实践

    目录 -RunLoop的概念 -RunLoop逻辑与实现 -RunLoop在iOS中运用 -RunLoop实践 -...

  • runloop

    runloop是什么 runloop与线程有什么关系 runloop的原理 runloop的使用

  • 深入理解Runloop

    RunLoop 的概念 RunLoop 与线程的关系 RunLoop 对外的接口 RunLoop 的 Mode R...

网友评论

      本文标题:RunLoop 的坑

      本文链接:https://www.haomeiwen.com/subject/eysdrctx.html