61.含有RunLoop声明[weak self]会失效的原因

这段代码

        DispatchQueue(label: "Timer").async {[weak self] in
            guard let self = self else{return}
            self.runLoop = RunLoop.current
            RunLoop.current.add(timer, forMode: .defaultRunLoopMode)
            RunLoop.current.run()
            print("end")
          
            print("\(self.description)")
        }

即使在block中声明self为weak,但只要在RunLoop.current.run()前做guard let self = self else{return},但RunLoop.current.run()后面代码再度调用self将会强持有self

产生这个结果的三个条件:

block中声明[weak self];
RunLoop.current.run()前做guard let self = self else{return};
RunLoop.current.run()后面再度调用self

下面是测试结果

class TestsController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        // Do any additional setup after loading the view.
        self.view.backgroundColor = .white
//        runLoopTest()
//        runLoopTest2()
        runLoopTest3()
    }
    var timer:Timer?
    var runLoop:RunLoop?
    func runLoopTest() {
        var count = 0
        let timer = Timer(timeInterval: 2, repeats: true) { (timer) in
            print("\(count)")
            count += 1
        }
        self.timer = timer
        DispatchQueue(label: "Timer").async {[weak self] in
            //如果RunLoop.current.run()之后还有调用self,将会强持有self
            guard let self = self else{return}
            self.runLoop = RunLoop.current
            RunLoop.current.add(timer, forMode: .defaultRunLoopMode)
            RunLoop.current.run()
            print("end")
            
            print("\(self.description)")
        }
    }
    /*结果:
      0
      1
      2
      ......
     即使pop后依然会继续timer
     */
    
    //正常运行
    func runLoopTest2() {
        var count = 0
        let timer = Timer(timeInterval: 2, repeats: true) { (timer) in
            print("\(count)")
            count += 1
        }
        self.timer = timer
//        DispatchQueue(label: "Timer").async {[unowned self] in//使用无主引用会崩溃,因为self已为nil,再调用会崩
        DispatchQueue(label: "Timer").async {[weak self] in
            self?.runLoop = RunLoop.current
            RunLoop.current.add(timer, forMode: .defaultRunLoopMode)
            RunLoop.current.run()
            print("end")
            print("\(self?.description ?? "nil")")
        }
    }
    /*结果:
     0
     1
     2
     deinit
     end
     nil
     */
    //正常运行
    func runLoopTest3() {
        var count = 0
        let timer = Timer(timeInterval: 2, repeats: true) { (timer) in
            print("\(count)")
            count += 1
        }
        self.timer = timer
//        DispatchQueue(label: "Timer").async {[unowned self] in//使用无主引用会崩溃
        DispatchQueue(label: "Timer").async {[weak self] in
            self?.runLoop = RunLoop.current
            RunLoop.current.add(timer, forMode: .defaultRunLoopMode)
            RunLoop.current.run()
            print("end")
            //写在RunLoop.current.run()之后就不会强持有,不过self已是nil,不会有打印
            guard let self = self else{return}
            print("\(self.description)")
        }
    }
    /*结果:
     0
     1
     deinit
     end
     */
    deinit {
        print("deinit")
        self.timer?.invalidate()
        if let rl = self.runLoop?.getCFRunLoop() {
            CFRunLoopStop(rl)
        }
    }
}