gpt4 book ai didi

swift - 闭包中的无主 self

转载 作者:搜寻专家 更新时间:2023-10-31 19:33:58 26 4
gpt4 key购买 nike

如果我在另一个闭包中有一个闭包,是否足以在外部闭包中使用 unowned/weak once 来避免保留循环?

例子:

foo.aClosure({[unowned self] (allowed: Bool) in
if allowed {
self.doStuff()

self.something.anotherClosure({ (s:String) -> (Void) in
self.doSomethingElse(s)
})
}
})

最佳答案

如果您没有在外部闭包中创建对 self 的强引用(例如通过这样做:guard let strongSelf = self else {返回 }).

如果您确实在闭包中创建了强引用,则必须向内部闭包添加一个捕获列表,以确保它弱捕获您对 self 的强引用。

这里有一些例子:

import Foundation
import PlaygroundSupport

class SomeObject {
typealias OptionalOuterClosure = ((Int) -> Void)?
typealias InnerClosure = () -> Void

var outerClosure: OptionalOuterClosure

func setup() {
// Here are several examples of the outer closure that you can easily switch out below
// All of these outer closures contain inner closures that need references to self

// optionalChecks
// - has a capture list in the outer closure
// - uses the safe navigation operator (?) to ensure that self isn't nil
// this closure does NOT retain self, so you should not see the #2 calls below
let optionalChecks: OptionalOuterClosure = { [weak self] callNumber in
print("outerClosure \(callNumber)")

self?.delayCaller { [weak self] in
print("innerClosure \(callNumber)")
self?.doSomething(callNumber: callNumber)
}
}

// copiedSelfWithInnerCaptureList
// - has a capture list in the outer closure
// - creates a copy of self in the outer closure called strongSelf to ensure that self isn't nil
// - has a capture list in the inner closure
// - uses the safe navigation operator (?) to ensure strongSelf isn't nil
// this closure does NOT retain self, so you should not see the #2 calls below
let copiedSelfWithInnerCaptureList: OptionalOuterClosure = { [weak self] callNumber in
guard let strongSelf = self else { return }
print("outerClosure \(callNumber)")

strongSelf.delayCaller { [weak strongSelf] in
print("innerClosure \(callNumber)")
strongSelf?.doSomething(callNumber: callNumber)
}
}

// copiedSelfWithoutInnerCaptureList
// - has a capture list in the outer closure
// - creates a copy of self in the outer closure called strongSelf to ensure that self isn't nil
// - does NOT have a capture list in the inner closure and does NOT use safe navigation operator
// this closure DOES retain self, so you should see the doSomething #2 call below
let copiedSelfWithoutInnerCaptureList: OptionalOuterClosure = { [weak self] callNumber in
guard let strongSelf = self else { return }
print("outerClosure \(callNumber)")

strongSelf.delayCaller {
print("innerClosure \(callNumber)")
strongSelf.doSomething(callNumber: callNumber)
}
}

// retainingOuterClosure
// - does NOT have any capture lists
// this closure DOES retain self, so you should see the doSomething #2 call below
let retainingOuterClosure: OptionalOuterClosure = { callNumber in
print("outerClosure \(callNumber)")

self.delayCaller {
print("innerClosure \(callNumber)")
self.doSomething(callNumber: callNumber)
}
}

// Modify which outerClosure you would like to test here
outerClosure = copiedSelfWithInnerCaptureList
}

func doSomething(callNumber: Int) {
print("doSomething \(callNumber)")
}

func delayCaller(closure: @escaping InnerClosure) {
delay(seconds: 1, closure: closure)
}

deinit {
print("deinit")
}
}

// Handy delay method copied from: http://alisoftware.github.io/swift/closures/2016/07/25/closure-capture-1/
func delay(seconds: Int, closure: @escaping () -> Void) {
let time = DispatchTime.now() + .seconds(seconds)
DispatchQueue.main.asyncAfter(deadline: time) {
print("🕑")
closure()
}
}

var someObject: SomeObject? = SomeObject()
someObject?.setup()

// Keep a reference to the outer closure so we can later test if it retained someObject
let copiedOuterClosure = someObject!.outerClosure!

// Call the outer closure once just to make sure it works
copiedOuterClosure(1)

// Wait a second before we destroy someObject to give the first call a chance to work
delay(seconds: 1) {
// Run the outerClosure again to check if we retained someObject
copiedOuterClosure(2)

// Get rid of our reference to someObject before the inner closure runs
print("de-referencing someObject")
someObject = nil
}

// Keep the main run loop going so our async task can complete (need this due to how playgrounds work)
PlaygroundPage.current.needsIndefiniteExecution = true

关于swift - 闭包中的无主 self ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37837862/

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