Swift中的捕获列表语法似乎存在一个奇怪的语法故障。如果我声明多个捕获的变量,捕获说明符仅适用于第一个:
let closure = { [unowned x, y] in … }
现在我希望y
为unowned
,但似乎并非如此:
class Test {
var callback: (Void -> Void)?
init() {
print("init")
}
deinit {
print("deinit")
}
}
func makeScope() {
let x = Test()
let y = Test()
y.callback = { [unowned x, y] in
print(y)
}
}
makeScope()
print("done")
打印:
init
init
deinit
done
因此y
似乎被强烈捕获并创建一个保留周期,从而阻止对象被释放。是这样吗?如果是,在列表中允许“空”捕获说明符是否有意义?或者是否有[unowned x, y]
未被视为[unowned x, unowned y]
的原因?
答案 0 :(得分:8)
...允许列表中的“空”捕获说明符是否有意义?
是的。 捕获说明符("弱","无主"及其变体)只能与引用类型一起使用,但也有一些情况需要捕获值类型 (这是一个例子: Pass value to closure?)。
您还可能想要强烈捕获引用类型。 捕获引用类型可确保引用(指针) 本身是按值捕获的,如以下示例所示:
class MyClass {
let value : String
init(value : String) {
self.value = value
}
}
var ref = MyClass(value: "A")
let clo1: () -> Void = { print(ref.value) }
let clo2: () -> Void = { [ref] in print(ref.value) }
ref = MyClass(value: "B")
clo1() // Output: B
clo2() // Output: A
执行第一个闭包时,闭包内ref
是对MyClass(value: "B")
创建的对象的引用。
第二个闭包在当时捕获ref
的值
已创建闭包,并且在新值时不会更改
被分配到var ref
。
答案 1 :(得分:1)
根据syntax EBNF,对unowned
捕获说明符的这种处理是完全有意的:
closure-signature→parameter-clause function-result opt
in
closure-signature→identifier-list function-result optin
closure-signature→capture-list parameter-clause function-result optin
closure-signature→capture-list identifier-list function-result optin
closure-signature→捕获列表in
capture-list→[capture-list-items]
capture-list-items→capture-list-item capture-list-item,
capture-list-items
capture-list-item→capture-specifier opt 表达式
capture-specifier→weak
|unowned
|unowned(safe)
|unowned(unsafe)
定义<capture-list-items>
,<capture-list-item>
和<capture-specifier>
制作的底部的三行与此处最相关。
<capture-list-items>
制作是逗号分隔的<capture-list-item>
列表,capture-specifier
附加到每个<capture-list-item>
,而不是<capture-list-items>
列表一个整体。
这很有道理,因为它使程序员可以完全控制各个参数的捕获。当说明符适用于整个列表时,替代方案将消除这种灵活性。
为什么要在捕获列表中包含标识符而不修改其捕获说明符?
Swift设计师的理念似乎是在可能的情况下提供智能默认行为。在大多数情况下,Swift可以找到一种方法来捕获基于表达式类型最有意义的表达式,而无需程序员的任何参与。当编译器没有足够的信息来确定基于上下文捕获变量的正确方法时,显式捕获说明符留给特殊情况。
答案 2 :(得分:0)
回答您的具体问题:
为什么捕获列表中的捕获说明符是可选的?
因为默认行为是捕获任何必要的变量(强烈捕获引用类型)。默认情况下,如果要使用其值,则无需在捕获列表中显式指定它们。 (如果您正在捕获self.property
,则需要使用self
进行资格认证。)
...是否有
[unowned x, y]
未被视为[unowned x, unowned y]
的原因?
出于同样的原因:默认是强烈捕获。 unowned
不适用于捕获列表中的其他项目;这不是语法现在如何运作。