【问题标题】:Does using a function as a closure retain self?使用函数作为闭包会保留自我吗?
【发布时间】:2018-06-03 08:08:53
【问题描述】:

我无法跟踪保留周期。我认为这与我订阅事件的方式有关。伪代码是这样的:

override func viewDidLoad() {
   func handleEvent() {
     self.doSomething()
   }

   subscribe("eventName", block: handleEvent)
}

deinit {
    unsubscribe("eventName")
} 

这会为自己/我的 ViewController 创建一个保留周期吗?如果是这样,我该如何绕过它?如果我使用的是闭包,我可以使用 [weak self],但是由于我正在传递一个函数,所以无论如何要使用 [weak self] 等价物吗?

【问题讨论】:

  • 那个问题是关于闭包的,我问的是使用函数作为闭包。不能将弱自身与函数一起使用。
  • 读错了你的代码……我的错。就一秒
  • 我们需要知道subscribe 对传递的闭包做了什么,以确定您是否有保留周期。如果它只是调用它而不存储它或将它捕获在另一个闭包中然后存储(在selfself 有强烈引用的东西上),那么就没有保留周期。如果它确实存储/捕获,那么是的,你有一个保留周期。如果您可以将代码归结为minimal reproducible example,那将是最有帮助的。
  • “我在跟踪保留周期时遇到问题” Instruments 告诉你什么?

标签: swift retain-cycle


【解决方案1】:

长话短说,您的代码确实保留了引用。 (handleEvent->viewDidLoad->self), http://blog.xebia.com/function-references-in-swift-and-retain-cycles/ 有一些通用的策略来避免这个问题。我的建议是创建一个函数引用,而不是声明一个函数:

let eventHandler: () -> () = { [weak self] in 
    self?.doSomething() 
}
subscribe("eventName", block: eventHandler)

【讨论】:

  • 这基本上就是我要说的。 OP 的语法问题的答案是匿名函数(包括分配为 var 值的函数)允许捕获列表语法,而命名函数声明则不允许。但是 OP 的情况是否真的会导致一个保留循环是不可能的; OP没有提供足够的信息。这取决于 subscribe 做了什么以及它的 block 参数的命运是什么(正如 Hamish 正确指出的那样)——而 OP 已经隐藏了这些信息。
  • @matt 很明显,它是事件处理并且需要在 deinit 中取消订阅推断事件可能/应该在实例消失后触发。存储函数引用将阻止这种情况发生。
【解决方案2】:

如果您从类内部引用属性或方法,它将创建一个保留循环。

class SomeClass {
  val a: (block: (() -> ()) -> ()) = ...

  func run() {
     func b() {
        print("Hello, World!")
     }

     func c() {
        self.someMethod()
     }

     func d() { [weak self] 
        self?.someMethod()
     }

     a(block: b) // no retain cycle
     a(block: c) // retain cycle
     a(block: d) // no retain cycle
  }

  func someMethod() {
     print("Hello, World!")
  }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-07-14
    • 2022-12-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多