ios - 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)
}
解决方案
您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
具有相同的值- 有你的循环。self
someFunctionWithNonescapingClosure
在堆栈跟踪中,您还将看到“部分应用”之类的条目 - 这是提供的参数 ( { 42 }
) 和隐式捕获的参数self
被收集并传递给someFunctionWithNonescapingClosure()
.
如果您将代码更改为:
init()
{
closure = Cycle.someFunctionWithNonescapingClosure
}
static func someFunctionWithNonescapingClosure(closure: () -> Int)
{
print("Hello") // breakpoint on this line
}
也就是说,在实例上创建someFunctionWithNonescapingClosure
一个类(static
)方法,然后当前类实例不会在闭包中捕获,并且您将不会得到循环。
高温高压
推荐阅读
- android - 使用资源文件夹中的字符串时捕获照片android异常
- javascript - Object.assign() 保留所有未更改的值
- sql - 如何设置小时和分钟大于给定日期的日期?
- python - Python; 将矩阵转换为二值化版本(基数 2)
- c# - 如何使用 System.XAML 定义来自多个输入行的值在 C#/WPF 中注释 XAML 文件的一行
- php - 如果用户购买特定产品,将早期订单的订单状态更改为“已取消”
- openshift - openshift 容器平台内的服务可发现性
- asp.net - “跟随”功能的业务逻辑。并发问题
- c# - Winforms/WPF 互操作 - 调整嵌套用户控件的大小
- here-api - Here-API Incidents API prox ApplicationError/InvalidInputData