2017-05-30 34 views
1
let observer = CFRunLoopObserverCreateWithHandler(kCFAllocatorDefault, CFRunLoopActivity.BeforeWaiting.rawValue, false, 0, { (observer, activity) in 

     self.doSomething() 

    }) 

    CFRunLoopAddObserver(CFRunLoopGetCurrent(), observer, UITrackingRunLoopMode) 

我在UIViewController中添加一个观察者到主runloop,这意味着self是UIViewController的一个实例。上面的代码创建了一个保留周期,导致控制器永远不会被释放。添加观察员runloop创建保留周期

我知道我可以声明[weak self]或[unowned self]来解决问题。我想问一下,retian循环是什么样的?我只知道这个街区能够以强烈的参照捕捉自我。

回答

0

在你的问题代码中没有保留周期。

  • 运行循环保留观察者。
  • 观察员保留该块。
  • 该块保留self

这不是保留周期。

但是,如果存储observerstrong实例变量,那么你有一个保留周期:

  • self保留了观察员。
  • 观察员保留该块。
  • 该块保留self
+0

我确信我没有将观察者存储在强实例变量中。如果我没有宣布自己是弱自我的,那么它就永远不会被释放, – itenyh

+0

你是否曾经从运行循环中移除观察者?如果您不从运行循环中删除观察者,那么观察者将永远不会被释放。如果观察者永远不会被释放,块将永远不会被释放。如果该块永远不会被释放,视图控制器将永远不会被释放。这并不意味着有一个保留周期! –

0

如果你用“的malloc堆栈”功能运行此在“调试内存图”开启(和“malloc的涂鸦”,以减少误报),你会看到什么是挂在您的视图控制器:

enter image description here

因为我们开启“的malloc栈”功能,可以在右边的堆栈上点击,它会带你直接到成立,强有力的参考代码。

如果你想看到更多的是传统的强引用循环图,你可以保持很强的参考你的观察:

class ViewController: UIViewController { 

    var observer: CFRunLoopObserver! 

    override func viewDidLoad() { 
     super.viewDidLoad() 

     DispatchQueue.global().async { 
      self.observer = CFRunLoopObserverCreateWithHandler(kCFAllocatorDefault, CFRunLoopActivity.beforeWaiting.rawValue, false, 0) { (observer, activity) in 
       self.doSomething() 
      } 

      CFRunLoopAddObserver(CFRunLoopGetCurrent(), self.observer, .commonModes) 
     } 
    } 

    func doSomething() { 
     // this is intentionally blank 
    } 

    deinit { 
     print("deinit") 
    } 
} 

然后你就可以在运行时错误看到更多实际的强引用循环清楚地说明:

enter image description here

但是,即使你的第一个例子是要保持一个强有力的参考视图控制器,但“调试内存图”,而它说明你的强引用,找到循环的根源(即那个挂在它上面的运行循环)更困难,所以你没有看到漂亮的循环图。但它仍然显示你的问题,但只是不作为运行时错误。

WWDC 2016 Visual Debugging with Xcode中概述的“调试内存图”功能从该视频的大约24分钟开始,将向您展示如何诊断这些类型的问题。