首页 > 解决方案 > Swift 中奇怪的保留周期

问题描述

所以我写了一些代码来更好地保持循环。

class AnotherViewController : UIViewController{

var closure : ((() -> Int) -> ())!


override func viewDidLoad() {
    super.viewDidLoad()

    closure = self.someFunctionWithNonescapingClosure

}

func someFunctionWithNonescapingClosure(closure: () -> Int) {
    //        closure()
}

}

显然,将 viewController 中的一个函数分配给属性闭包,会导致保留周期问题。

但我不知道怎么做?

Self 对 Closure 有一个强引用 但是,在 viewController tp Closure 中分配一个函数,是否对 self 进行了一个强引用?

谢谢

编辑 - - -

显然,如果您通过创建 AnotherViewController 在 Playground 中尝试此操作,对其进行初始化并将其分配给变量,然后将变量设置为 nil,它将成功地 deinit AnotherViewController,但如果您在应用程序中尝试,AnotherViewController 不会被剥夺。

你可以尝试给AnotherViewController添加一个按钮并关闭它,为方便起见,按钮代码是这样的

 private func addAButton(){
    let button = UIButton()
    let buttonBounds = CGRect(x: 0, y: 0, width: 200, height: 200)
    let buttonCenter = view.center
    button.bounds = buttonBounds
    button.center = buttonCenter

    view.addSubview(button)

    button.backgroundColor = .red

    button.addTarget(self, action: #selector(goBack), for: .touchUpInside)
}

@objc func goBack(){
    dismiss(animated: true, completion: nil)
}

标签: iosswift

解决方案


closure被分配了一个实例方法,该方法隐式捕获self,因此是循环。

尝试以下应用程序:

import Cocoa

class Cycle
{
  var closure : ((() -> Int) -> ())!

  init()
  {
     closure = self.someFunctionWithNonescapingClosure
  }

  func someFunctionWithNonescapingClosure(closure: () -> Int)
  {
     print("Hello") // breakpoint on this line
  }
}

@NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate
{
  @IBOutlet weak var window: NSWindow!

  func applicationDidFinishLaunching(_ aNotification: Notification)
  {
     let aCycle = Cycle()
     aCycle.closure({ 42 })
  }
}

在行上添加断点print并运行应用程序。

someFunctionWithNonescapingClosure()该应用程序将在由 调用的内部停止aCycle.closure({ 42 })

查看变量显示,有一个self. 这是因为每个实例方法都有一个隐式 self参数。

在您的代码中,它是self从哪里来的?

当线:

closure = self.someFunctionWithNonescapingClosure

被执行 Swift 捕获的当前值self作为隐式参数传递给,它必须这样做,因为您正在从实例方法someFunctionWithNonescapingClosure()创建闭包。

所以你有你的循环,分配给的闭包closure包含对self.

要查看此注释,请注意self调试器停止时的值,然后applicationDidFinishLaunching在堆栈跟踪中选择条目并查看其变量 - 它与ofaCycle具有相同的值- 有你的循环。selfsomeFunctionWithNonescapingClosure

在堆栈跟踪中,您还将看到“部分应用”之类的条目 - 这是提供的参数 ( { 42 }) 和隐式捕获的参数self被收集并传递给someFunctionWithNonescapingClosure().

如果您将代码更改为:

  init()
  {
     closure = Cycle.someFunctionWithNonescapingClosure
  }

  static func someFunctionWithNonescapingClosure(closure: () -> Int)
  {
     print("Hello") // breakpoint on this line
  }

也就是说,在实例上创建someFunctionWithNonescapingClosure一个类(static)方法,然后当前类实例不会在闭包中捕获,并且您将不会得到循环。

高温高压


推荐阅读