为什么在类需要的结构中声明self
不需要?我不知道是否还有其他示例,但是使用转义的闭包,是这样。如果闭包是非可选的(因此是不可转义的),则无需在两者之一中声明self
。
class SomeClass {
let someProperty = 1
func someMethod(completion: (() -> Void)?) {}
func anotherMethod() {
someMethod {
print(self.someProperty) // declaring self is required
}
}
}
struct SomeStruct {
let someProperty = 1
func someMethod(completion: (() -> Void)?) {}
func anotherMethod() {
someMethod {
print(someProperty) // declaring self is not required
}
}
}
答案 0 :(得分:5)
在转义的闭包(无论是可选的闭包还是显式标记为self
的内部)中使用属性时,包括@escaping
的目的是使捕获语义明确。如编译器警告我们,如果我们删除self
参考,
在闭包中引用属性'someProperty'要求显式使用'self'以使捕获语义明确。
但是结构没有捕获模棱两可的语义。您始终在转义的闭包内部处理副本。引用类型仅是模棱两可的,您需要在self
上清楚说明可能在何处引入强引用周期,要引用的实例等。
顺便说一句,对于类类型,将self
与属性一起引用并不是使捕获语义明确的唯一方法。例如,您可以使用“捕获列表”使意图明确:
仅捕获属性:
class SomeClass {
var someProperty = 1
func someMethod(completion: @escaping () -> Void) { ... }
func anotherMethod() {
someMethod { [someProperty] in // this captures the property, but not `self`
print(someProperty)
}
}
}
或捕获self
:
class SomeClass {
var someProperty = 1
func someMethod(completion: @escaping () -> Void) { ... }
func anotherMethod() {
someMethod { [self] in // this explicitly captures `self`
print(someProperty)
}
}
}
这两种方法都可以使您清楚地捕获所捕获的内容。
答案 1 :(得分:3)
对于类,闭包提供一种增加引用计数的机制,从而“使对象保持活动状态”。
也许您只需捕获someProperty
就可以了。也许不吧!编译器不知道您是否使用闭包来增加引用,因此可以使您清楚自己的意图。
不仅那是没有结构的问题,而且突变的可能性也是如此,这是严格禁止的。
假设您希望anotherMethod
在结构中允许任何类型的突变。您可以先将其标记为变异…
struct SomeStruct {
func someMethod(completion: (() -> Void)?) {}
mutating func anotherMethod() {
someMethod {
self
}
}
}
…但是不,那是一个错误:
转义转义符捕获变异的'self'参数
尽管捕获self
……
mutating func anotherMethod() {
someMethod { [self] in
self
}
}
...那很好。
这也是Swift允许的唯一选项。在结构中使用转义的闭包时,只能使用实例的不可变捕获。即[self] in
是隐式的,用于非突变方法。
这会产生意想不到的结果。小心点。
struct SomeStruct {
var someProperty = 1
func anotherMethod() {
DispatchQueue.global().asyncAfter(deadline: .now() + 1) {
print(someProperty)
}
}
}
var s = SomeStruct()
s.anotherMethod() // 1, even though it's printed after the following reassignment
s.someProperty = 2
s.anotherMethod() // 2
我认为思考一下方法语法的简写会有所帮助。
s.anotherMethod()
是真的
SomeStruct.anotherMethod(s)()
您可以看到那里的不变性,因为这里没有&。