gpt4 book ai didi

ios - 将闭包保存为变量的理解

转载 作者:可可西里 更新时间:2023-11-01 01:06:22 25 4
gpt4 key购买 nike

我正在 Playground 上测试这段代码(我正在使用 UnsafeMutablePointers 来模拟取消初始化):

class TestClassA {

func returnFive() -> Int {
return 5
}

deinit {
println("Object TestClassA is destroyed!") //this way deinit is not called
}
}

class TestClassB {

let closure: () -> Int

init(closure: () -> Int) {
self.closure = closure
}

deinit {
println("Object TestClassB is destroyed!")
}
}

let p1 = UnsafeMutablePointer<TestClassA>.alloc(1)
p1.initialize(TestClassA())

let p2 = UnsafeMutablePointer<TestClassB>.alloc(1)
p2.initialize(TestClassB(closure: p1.memory.returnFive))

p2.memory.closure()
p1.memory.returnFive()


p1.destroy()

但是,当我将 TestClassB 的初始化更改为:

p2.initialize(TestClassB(closure: {p1.memory.returnFive()}))

现在可以取消初始化 TestClassA。

谁能告诉我,这两者有什么区别

TestClassB(closure: p1.memory.returnFive)

TestClassB(closure: {p1.memory.returnFive()})

为什么在第二种情况下没有对 TestClassA 的强引用,所以它可以被取消初始化?

最佳答案

这里的问题是使用 UnsafeMutablePointer<SomeStruct>.memory .重要的是不要陷入认为 memory 的陷阱就像一个包含指向对象的存储属性,只要指针存在,它就会保持事件状态。尽管感觉像一个,但它不是,它只是原始内存。

这是一个只使用一个类的简化示例:

class C {
var x: Int
func f() { println(x) }

init(_ x: Int) { self.x = x; println("Created") }
deinit { println("Destroyed") }
}

let p = UnsafeMutablePointer<C>.alloc(1)
p.initialize(C(42))
p.memory.f()
p.destroy() // “Destroyed” printed here
p.dealloc(1)
// using p.memory at this point is, of course, undefined and crashy...
p.memory.f()

但是,假设您复制了 memory 的值,并将其分配给另一个变量。这样做会增加对象的引用计数 memory指向(就像您复制了另一个常规类引用变量一样:

let p = UnsafeMutablePointer<C>.alloc(1)
p.initialize(C(42))
var c = p.memory
p.destroy() // Nothing will be printed here
p.dealloc(1)
// c has a reference
c.f()
// reassigning c decrements the last reference to the original
// c so the next line prints “Destroyed” (and “Created” for the new one)
c = C(123)

现在,假设您创建了一个捕获 p 的闭包,并在 p.destroy() 之后使用它的内存被称为:

let p = UnsafeMutablePointer<C>.alloc(1)
p.initialize(C(42))
let f = { p.memory.f() }
p.destroy() // “Destroyed” printed here
p.dealloc(1)
// this amounts to calling p.memory.f() after it's destroyed,
// and so is accessing invalid memory and will crash...
f()

但是,对于您的情况,如果您只是分配 p.memory.ff , 完全没问题:

let p = UnsafeMutablePointer<C>.alloc(1)
p.initialize(C(42))
var f = p.memory.f
p.destroy() // Nothing will print, because
// f also has a reference to what p’s reference
// pointed to, so the object stays alive
p.dealloc(1)
// this is perfectly fine
f()
// This next line will print “Destroyed” - reassigning f means
// the reference f has to the object is decremented, hits zero,
// and the object is destroyed
f = { println("blah") }

那怎么会f捕获值(value)?

正如@rintaro 所指出的,Swift 中的成员方法是柯里化(Currying)函数。想象一下没有成员方法。相反,只有常规函数和具有成员变量的结构。你怎么能写出等价的方法呢?你可能会这样做:

// a C.f method equivalent.  Using this
// because self is a Swift keyword...
func C_f(this: C) {
println(this.x)
}
let c = C(42)
// call c.f()
C_f(c) // prints 42

Swift 更进一步,“套用”了第一个参数,这样你就可以写成 c.f并获得绑定(bind) f 的函数到 C 的特定实例:

// C_f is a function that takes a C, and returns
// a function ()->() that captures the this argument:
func C_f(this: C) -> ()->() {
// here, because this is captured, it’s reference
// count will be incremented
return { println(this.x) }
}

let p = UnsafeMutablePointer<C>.alloc(1)
p.initialize(C(42))
var f = C_f(p.memory) // The equivalent of c.f
p.destroy() // Nothing will be destroyed
p.dealloc(1)
f = { println("blah") } // Here the C will be destroyed

这等同于您原始问题代码中的捕获,应该显示为什么您没有看到原始 A 对象被销毁。

顺便说一句,如果你真的想使用闭包表达式来调用你的方法(假设你想在之前或之后做更多的工作),你可以使用变量捕获列表:

let p = UnsafeMutablePointer<C>.alloc(1)
p.initialize(C(42))
// use variable capture list to capture p.memory
let f = { [c = p.memory] in c.f() }
p.destroy() // Nothing destroyed
p.dealloc(1)
f() // f has it’s own reference to the object

关于ios - 将闭包保存为变量的理解,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28384805/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com