【问题标题】:How to remove strong reference cycle from closure from method?如何从方法的闭包中删除强引用循环?
【发布时间】:2017-02-15 09:06:08
【问题描述】:

这里我有一些关于闭包强引用循环的例子。 如果我将一个闭包分配给一个存储的属性,我可以使用一个闭包捕获列表来使捕获的引用无主/弱。 但是,如果我将方法分配给存储的属性闭包或将方法分配给外部范围内的闭包,我将无法使用捕获列表。

如何去除最后两种情况下的引用循环?

使用仅闭包的捕获列表创建和避免强引用循环的示例

internal class ClosureClass {
    internal let p1: String
    internal lazy var p2: () -> String = {
        [unowned self] // if you comment this out there is a strong reference cycle
        () -> String in
        return self.p1
    }

    internal init() {
        self.p1 = "Default value of ClosureClass"
    }

    deinit {
        print("Object with property '\(self.p1)' is being deinitialized")
    }
}
print("Test 'Closure with strong reference to self':")
var cc: ClosureClass? = ClosureClass.init()
cc!.p2() // lazy need to call it once, else it will not be initiliazed
cc = nil

使用方法闭包创建强引用循环的示例

internal class MethodToClosureClass {

    internal let p1: String
    internal lazy var p2: () -> String = method(self) // Why not self.method ? Will create a strong reference cycle, but I can not set the reference to weak or unowned like in closures with the closure capture list

    internal init() {
        self.p1 = "Default value of MethodToClosureClass"
    }

    internal func method() -> String {
        //      [unowned self] in
        return self.p1
    }

    deinit {
        print("Object with property '\(self.p1)' is being deinitialized")
    }
}
print("Test 'Set closure with method intern':")
var m2cc: MethodToClosureClass? = MethodToClosureClass.init()
m2cc!.p2() // lazy need to call it once, else it will not be initiliazed
m2cc = nil

通过从外部方法设置闭包来创建强引用循环的示例

internal class MethodClass {
    internal let p1: String
    internal var p2: () -> String = {
        return ""
    }

    internal init() {
        self.p1 = "Default value of MethodClass"
    }

    internal func method() -> String {
        //      [unowned self] in
        return self.p1
    }

    deinit {
        print("Object with property '\(self.p1)' is being deinitialized")
    }
}
print("Test 'Set closure with method extern':")
var mc: MethodClass? = MethodClass.init()
var method: () -> String = mc!.method // will create a strong reference
mc!.p2 = method
mc = nil

输出

测试“强引用自我的闭包”:

正在取消初始化具有属性“ClosureClass 的默认值”的对象

测试'使用方法实习生设置闭包':

测试'使用外部方法设置闭包':

【问题讨论】:

  • 无关:您可以使用self.method 代替method(self)。此外,您不需要将所有内容都注释为internal,这是默认设置。
  • @Hamish 哦有趣,Xcode 8 不建议 method 如果在属性关闭的情况下写 self.,缺少功能或错误,但是当我写的时候它给了我method(self) 的建议meth。感谢您指出。有趣的是,method 对于属性来说是不够的,但对于外部范围内的变量来说就足够了。
  • 需要self.method 而不仅仅是methodlazy 属性的一个怪癖——它们需要显式使用self.,例如this Q&A

标签: methods closures swift3 capture-list reference-cycle


【解决方案1】:

self.method 只是一个用于创建闭包的语法糖(使用默认的捕获模式,这很强大):{ () in self.method() }。如果您想使用显式捕获列表,请不要使用语法糖——显式创建一个闭包(无论如何它都是这样做的):

{ [unowned self] () in self.method() }

【讨论】:

  • 哦,好的,我明白了。 self.methodmethod(self) 返回带有方法定义大括号中代码的闭包。所以如果你写self.method(),你并没有避免用self.method创建闭包,只是在之后执行它并将它打包到另一个闭包中以获得unowned/weak语义。
  • @Hamish:嗯,我不知道编译器是如何实现它们的。但从语言的角度来看,它们在语义上似乎是等价的。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-04-28
  • 1970-01-01
  • 1970-01-01
  • 2015-05-06
  • 1970-01-01
相关资源
最近更新 更多