在不冒漏的闭包中包含(或不包括)捕获列表有什么区别?

时间:2019-03-05 13:22:33

标签: swift

这是我的代码:

class Person { 
    let age: Int

    init(age: Int) { 
        self.age = age
    }

    func callAgePrinter() { 
        // THIS LINE
        AgePrinter.printAgeOf(person: { return self } )
    }
}

class AgePrinter {
    static func printAgeOf(person: () -> (Person)) { 
        print(person().age)
    }
}

Person(age: 1).callAgePrinter()

请注意评论:// THIS LINE

我能够转换此行:

AgePrinter.printAgeOf(person: { return self } )

收件人:

AgePrinter.printAgeOf(person: { [unowned self] in return self } )

代码的结果是相同的。

我想知道:对于不冒名的闭包(仅在函数声明级别适用于Swift 4.2),捕获列表的用途是什么?对于不漏掉的闭包,可以保证在结束(或可能不)调用闭包的方法结束之后,闭包消失并且不再存储。

当然,在我的示例中,存储闭包的输出时仍会发生保留周期。但是,捕获周期并不能阻止这种情况。

在不冒号的闭包中包含(或不包括)捕获列表有什么区别?

2 个答案:

答案 0 :(得分:2)

Capture将信息复制到新变量中。我的意思是[unowned self]创建另一个实际上不是self的{​​{1}}变量。

答案 1 :(得分:2)

self使用捕获列表是很常见的,但这不是其唯一目的。捕获列表捕获任意值。 “捕获”的意思是“制作自己的卷影副本,而不是覆盖范围内的值”。考虑以下代码:

var a = 10

let f: () -> Void = { print("f: \(a)") }

let g: () -> Void = { [a] in print("g: \(a)") }

a = 20
f()   // f: 20; using "a" from the local scope surrounding f()
g()   // g: 10; using "a" that was copied into g()

作为一个稍微复杂一点的示例,请考虑以下(不正确的)代码,在该代码中,我们使用需要从一个动作到另一个动作递增的值来累积一些要执行的动作:

var actions: [() -> Void] = []

var opId = 0
if someCase {
    opId += 1
    actions.append({ doSomethingWith(opId) })
}
if anotherCase {
    opId +=1
    actions.append({ doSomethingElseWith(opId) })
}
//...
actions.forEach { $0() }

此代码不正确;所有的闭包都将具有相同的opId。但是,如果添加捕获列表,则可以解决问题:

actions.append({ [opId] in doSomethingWith(opId) })