为什么在类中需要声明 self 的结构中不需要声明 self ?

hga*_*ale 5 swift

为什么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
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

Rob*_*Rob 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)
             }
         }
     }
    
    Run Code Online (Sandbox Code Playgroud)
  • 或捕获self

     class SomeClass {
         var someProperty = 1
    
         func someMethod(completion: @escaping () -> Void) { ... }
    
         func anotherMethod() {
             someMethod { [self] in            // this explicitly captures `self`
                 print(someProperty)
             }
         }
     }
    
    Run Code Online (Sandbox Code Playgroud)

这两种方法还可以明确您正在捕获的内容。