Swift:嵌套闭包中的自引用

Posted

技术标签:

【中文标题】Swift:嵌套闭包中的自引用【英文标题】:Swift: self reference in nested closures 【发布时间】:2018-10-22 18:54:40 【问题描述】:

我在 Swift 中使用新的基于块的 KVO API 来观察属性。 下面是示例代码。

class A: NSObject 
var observerA: NSKeyValueObservation? = nil
var observerB: NSKeyValueObservation? = nil

var property1: CustomObj1?
var property2: CustomObj2?

func doSomething() 



func doSomethingElse() 



func observeValues() 
    observerA = customObj1.observe(\.property1, options: [], changeHandler:  [weak self] (obj, change) in
        guard let strongSelf = self else  return 
        strongSelf.doSomething()
        strongSelf.observerB = customObj2.observe(\.property2, options: [], changeHandler:  [weak strongSelf] (nestedObj, nestedChange) in
            guard let nestedStrongSelf = strongSelf else  return 
            nestedStrongSelf.doSomethingElse()
        )
    )

我的问题是我们如何在内部更改处理程序块中引用self。 我可以像上面那样使用它,而且我没有看到任何内存泄漏。但是在内部更改处理程序的“[weak strongSelf]”中使用self 代替strongSelf 也不会导致任何问题。这是代码。

func observeValues() 
observerA = self.observe(\.property1, options: [], changeHandler:  [weak self] (obj, change) in
    guard let strongSelf = self else  return 
    strongSelf.doSomething()
    strongSelf.observerB = strongSelf.observe(\.property2, options: [], changeHandler:  [weak self] (nestedObj, nestedChange) in
        guard let nestedStrongSelf = self else  return 
        nestedStrongSelf.doSomethingElse()
    )
)

我的问题是如何在嵌套的完成处理程序中引用 self,以及这方面的最佳实践是什么。谢谢。

【问题讨论】:

我为我之前的错误回答道歉!事实证明你是完全正确的。我总是使用[unowned self] 来处理这种情况。 你为什么不使用[weak self],因为你发现它没有问题? 是的,可以做到。但我最终还是使用了strongSelf 以获得更好的可读性。 【参考方案1】:

即使您有一个强引用循环,您也不会看到任何内存泄漏,直到所有其他强引用消失。

例如,如果这个 VC 在整个应用程序生命周期内都处于活动状态,即使闭包捕获了一个强引用循环,它也不会做任何事情。影响将是相同的:VC 将在整个应用程序生命周期内都处于活动状态,无论如何它已经在这样做了。

只有当你有一个强引用循环时,你才能识别内存泄漏,然后尝试通过删除所有其他强引用来取消初始化 VC。

【讨论】:

VC 在应用程序的整个生命周期内都不会存在,我希望在 VC 代表的屏幕关闭后释放 VC 及其模型控制器。我对上述代码没有任何保留问题。我正在寻找在嵌套更改处理程序中访问 self 的最佳方法。我应该在嵌套块中将 self 称为“self”,还是应该引用在父块的捕获列表中声明的 self(strongSelf) 的较弱版本。 @SwiftTechnocrat 因此,当您关闭该 VC 的屏幕时,您应该会在 Instruments 中看到内存泄漏。 是的,我确实看到了内存泄漏,并且当我没有在父块中声明 self 为弱时,deinit 永远不会执行。 @SwiftTechnocrat 是的,这是有道理的。我想我不明白你的问题,你在问什么?在nest scoped中,你要弱捕获self,同理。 是的,应该弱弱地捕获自我。在这种情况下,它是否被称为selfself 的弱版本(即strongSelf)并不重要。从技术上讲,两者是相同的。我的印象是使用嵌套块中的self 捕获列表可能会导致保留周期。感谢您的投入。

以上是关于Swift:嵌套闭包中的自引用的主要内容,如果未能解决你的问题,请参考以下文章

Swift 学习- 08 -- 闭包

➽06闭包

JS高级:闭包

JavaScript闭包

引用和函数引用,函数嵌套闭包,装饰器以及递归

Swift 中的利刃函数