2016-08-14 65 views
8

这里是我的自定义视图:斯威夫特保留周期解释

class CustomVIew: UIView { 

    deinit { 
     print("custom view deinit") 
    } 

    var onTapViewHandler: (()->Void)? 
} 

和视图控制器:

class ViewControllerB: UIViewController { 

    var customView: CustomVIew! 

    deinit { 
     print("B deinit") 
    } 

    override func viewDidLoad() { 
     super.viewDidLoad() 

     let customView = CustomVIew() 
     customView.onTapViewHandler = { [unowned self] in 
      self.didTapBlue() 
     } 
     customView.frame = CGRect(x: 50, y: 250, width: 200, height: 100) 
     customView.backgroundColor = UIColor.blueColor() 
     view.addSubview(customView) 

     self.customView = customView 

    } 

    func didTapBlue() { 

    } 
} 

当控制器从导航堆栈中弹出,一切都很好:

B deinit 
custom view deinit 

但是当我替换此代码时:

customView.onTapViewHandler = { [unowned self] in 
    self.didTapBlue() 
} 

与此:

customView.onTapViewHandler = didTapBlue 

那么,没有打印在控制台上。 CustomView和ViewController没有发布,为什么?

为什么customView.onTapViewHandler = didTapBlue捕获对self的引用?

+0

你知道为什么已经不是吗?你的标题说它是保留圈...通过打印检查引用计数:print(CFGetRetainCount(object)) – Surely

+0

@你确实建议'CFGetRetainCount'来解决'retain'的问题。但有一个原因,保留'已被弃用:这不是一个好的解决方案。 – Abizern

+0

这只是一种检查方法。我的意思是你可以输出视图控制器被引用的引用数量,以便你知道“customView”是否对视图控制器有很强的参考。如果有,则有一个保留周期。因为它有一个保留周期,所以这两个对象不能自动销毁。 – Surely

回答

4

如果将[unowned self]捕获列表添加到闭包中,该视图将持有对self的弱引用,并且self对该视图持有强烈的引用。

由于没有任何关于self的强烈参考,当弹出视图控制器时,可以取消初始化self。在self被初始化之后,没有任何东西对视图有强烈的参考,所以也被去初始化。

如果您删除捕获列表,self对该视图持有强烈的参考,并且该视图对self有强烈的参考。这意味着为了取消初始化self,视图必须首先被初始化(这将打破强引用)。但为了使视图被初始化,视图控制器必须首先被去初始化以打破对视图的强引用。但是,除非您取消初始化视图控制器,否则无法打破视图的强烈引用。除非取消初始化视图,否则不能分解对视图控制器的强引用。

请参阅?我们已经陷入了无限循环!所以视图和视图控制器都不会被初始化!

4

Swift函数是一种闭包。就像闭包(目标c中的块)功能可以捕获参考。

customView.onTapViewHandler = didTapBlue得到执行时引用selfViewControllerB引用在这种情况下将被函数调用捕获。

同时ViewControllerB的观点对CustomVIew持有强烈的参考,因此它使保留周期。

关于使用unownedApple document说:

弱和无主引用启用的参考周期 一个实例来指代其他实例,而无需保持强抱上它。 然后,实例可以互相引用,而不会创建强大的参考周期 。

这意味着没有循环引用和保留周期。

+0

thanks.I只是不明白为什么'customView.onTapViewHandler = didTapBlue'执行会捕获'self''参考,你能告诉我吗? –

+0

'didTapBlue'是'self.didTapBlue'。所以'customView'应该保存对'didTapBlue'的引用,只有这样它才能执行该函数。如你所知,didTapBlue如果没有对象的引用就无法生存。所以关闭,块和方法为实例添加了强大的参考 – renjithr

+0

哦!我懂了。非常感谢你!^ - ^ –