简体   繁体   English

在Swift中奇怪的保留周期

[英]Weird retain cycle in Swift

so I have written some codes to better under retain cycle. 所以我写了一些代码以更好地保持周期。

class AnotherViewController : UIViewController{

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


override func viewDidLoad() {
    super.viewDidLoad()

    closure = self.someFunctionWithNonescapingClosure

}

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

} }

So apparently, assigning one of the function in viewController to the property closure, it causes the retain cycle problem. 因此,显然,将viewController中的功能之一分配给属性闭包,会引起保留周期问题。

But I don know how? 但是我不知道怎么办?

Self has a strong reference to Closure But, does assigning a function in the viewController tp Closure, make a strong reference of self to closure? Self对Closure有很强的引用,但是,是否在viewController tp Closure中分配了一个函数,却对self有很强的引用?

Thanks 谢谢

EDIT ------ 编辑------

Apparently, if you try this in a playground by creating the AnotherViewController, initialize it and assign it to a variable, then set the variable to nil, it will successfully deinit the AnotherViewController, but if you try it in an app, the AnotherViewController will not get deinited. 显然,如果您在操场上通过创建AnotherViewController进行尝试,将其初始化并将其分配给变量,然后将该变量设置为nil,它将成功地取消初始化AnotherViewController,但如果在应用程序中进行尝试,AnotherViewController将不会成功取消初始化。

You can try to add a button to AnotherViewController and dismiss it, for convenience, the button code is this 您可以尝试将按钮添加到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)
}

Your closure is being assigned an instance method, which implicitly captures self , hence the cycle. 您的closure被分配了一个实例方法,该方法隐式捕获self ,因此捕获了循环。

Try the following app: 尝试以下应用:

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 })
  }
}

Add a breakpoint on the print line and run the app. print行上添加一个断点并运行该应用程序。

The app will stop inside someFunctionWithNonescapingClosure() which is called by aCycle.closure({ 42 }) . 该应用程序将停止内someFunctionWithNonescapingClosure()这是由称为aCycle.closure({ 42 })

Look at the variable display, there is a self . 看变量显示,有一个self This is because every instance method has an implicit self argument. 这是因为每个实例方法都有一个隐式的 self变量。

In your code where does that self come from? 在您的代码中,那个self是从哪里来的?

When the line: 当行:

closure = self.someFunctionWithNonescapingClosure

is executed Swift captures the current value of self to pass as the implicit argument to someFunctionWithNonescapingClosure() , it must do this as you are creating a closure from an instance method. 被执行时,Swift捕获self的当前值作为隐式参数传递给someFunctionWithNonescapingClosure() ,在您从实例方法创建闭包时必须执行此操作。

And so you have your cycle, the closure assigned to closure contains a reference to self . 这样便有了循环,分配给closure包含对self的引用。

To see this note the value of self when the debugger stops and then select the entry for applicationDidFinishLaunching in the stack trace and look at its aCycle variable - it has the same value as the self of someFunctionWithNonescapingClosure - there is your cycle. 要查看此注释,请在调试器停止运行时选择self的值,然后在堆栈跟踪中选择applicationDidFinishLaunching的条目,并查看其aCycle变量-它的值与someFunctionWithNonescapingClosureself值相同-存在您的周期。

In the stack trace you will also see entries like "partial apply" - this is where the supplied argument ( { 42 } ) and the implicitly captured self are collected and passed to someFunctionWithNonescapingClosure() . 在堆栈跟踪中,您还将看到诸如“ partial apply”之类的条目-这是收集提供的参数( { 42 } )和隐式捕获的self并将其传递给someFunctionWithNonescapingClosure()

If you change the code to: 如果将代码更改为:

  init()
  {
     closure = Cycle.someFunctionWithNonescapingClosure
  }

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

that is make someFunctionWithNonescapingClosure a class ( static ) method instead on an instance one then the current class instance is not captured in the closure and you will not get a cycle. 那就是使someFunctionWithNonescapingClosure成为一个实例上的类( static )方法,而不是在闭包中捕获当前的类实例,并且不会获得循环。

HTH HTH

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM