首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >闭包中的闭包中的无主自身

闭包中的闭包中的无主自身
EN

Stack Overflow用户
提问于 2016-06-15 22:08:36
回答 2查看 2.1K关注 0票数 5

如果我在另一个闭包中有一个闭包,那么在外部闭包中使用一次unowned/ have来避免保留循环是否足够?

示例:

代码语言:javascript
复制
foo.aClosure({[unowned self] (allowed: Bool) in
            if allowed {
                self.doStuff()

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

回答 2

Stack Overflow用户

发布于 2017-01-12 01:12:15

如果你没有在外部闭包中创建一个对self的强引用(例如,通过这样做: guard let strongSelf = self else { return }),那么仅在外部闭包的捕获列表中声明弱的或无主的self就足以避免保留循环。

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

下面是一些示例:

代码语言:javascript
复制
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
票数 4
EN

Stack Overflow用户

发布于 2016-06-15 22:53:22

是的,但是我会使用弱,而不是无主,因为self.doStuff()会抛出一个异常,如果没有,而如果你使用弱及其self?.doStuff(),就不会抛出异常,它就不会执行。

您可以在操场上使用以下代码进行测试:

代码语言:javascript
复制
typealias Closure = () -> Void

class ClosureObject {
    var closure:Closure?
    func saveClosure(closure:Closure?) {
        self.closure = closure
    }
}

let mainClosureObject = ClosureObject()

class TestObject {
    let closureObject = ClosureObject()
    func log() {
        print("logged")
    }
    func run() {
        mainClosureObject.saveClosure() {[weak self] in
            self?.closureObject.saveClosure() {
                self?.log()
            }
        }
    }
}

var testObject:TestObject? = TestObject()
let closureObject = testObject?.closureObject
testObject?.run()
mainClosureObject.closure?()
closureObject?.closure?()
testObject = nil
closureObject?.closure?()
mainClosureObject.closure?()
closureObject?.closure?()

并将其与以下内容进行比较:

代码语言:javascript
复制
typealias Closure = () -> Void

class ClosureObject {
    var closure:Closure?
    func saveClosure(closure:Closure?) {
        self.closure = closure
    }
}

let mainClosureObject = ClosureObject()

class TestObject {
    let closureObject = ClosureObject()
    func log() {
        print("logged")
    }
    func run() {
        mainClosureObject.saveClosure() {
            self.closureObject.saveClosure() {
                self.log()
            }
        }
    }
}

var testObject:TestObject? = TestObject()
let closureObject = testObject?.closureObject
testObject?.run()
mainClosureObject.closure?()
closureObject?.closure?()
testObject = nil
closureObject?.closure?()
mainClosureObject.closure?()
closureObject?.closure?()
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/37837862

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档