Swift 5.8 逃逸闭包中省略 self 关键字

922 阅读2分钟

逃逸闭包中隐藏 self

Swift 语言允许在很多地方使用隐藏式的 self 关键字,这种特性提升了开发效率,并且能够消除一定的视觉噪音,让开发者专注在更重要的代码逻辑上。

在最近更新的 Swift 5.8 中,Swift 扩展了这种能力,这使得隐式 self 可以在逃逸闭包中使用。

在 swift 5.8 之前,当我们在逃逸闭包中引用 self 时,逃逸闭包强引用 self,self 强引用这个闭包,有可能产生引用循环,因此 swift 要求这种情况必须显示的使用 self,这样能让开发者知道,这样做有循环引用的风险。

比如下边的代码:

override func viewDidLoad() {
    super.viewDidLoad()
    
    testMethod { [weak selfin
        guard let self = self else {
            return
        }
        testMethod2()
    }
}


func testMethod(success@escaping () -> Void) {
    DispatchQueue.main.asyncAfter(deadline: .now() + 3) {
        success()
    }
}

func testMethod2() {
    
}

testMethod 的回调里调用 testMethod2 方法,系统会报错:

图片

提示我们应该在 testMethod2 前增加 self 来明确捕获语义,即使我已经使用了 [weak self]

不得不说 swift 变得越来越聪明了,因为社区中有越来越多的开发者发现,有些情况下即使是在逃逸闭包中使用 self 也不会发生循环引用

例如

  • 当 self 是 struct/enum 等值类型时,不存在引用,也就不存在循环引用

  • 当在逃逸闭包中使用了 [weak self]  时,已经弱引用了 self,也就不存在内存不释放的问题

经过我的测试,相同的这段代码,在 swift 5.8 中能够正常编译通过,但是有几种情况需要注意

  • 如果没有使用 [weak self] 依然会报错

  • 如果只是使用 [weak self],但 self 没有解包,也依然会报错

  • 如果使用 [weak self],并且解包后的 self 不叫 self,也依然会报错

总结

在类的逃逸闭包中使用隐示 self,需要先 [weak self],并且把 self 解包,并且解包后的名字依然叫 self,以下两种方式都可以:

testMethod { [weak selfin
    guard let self = self else {
        return
    }
    testMethod2()
}

或者

testMethod { [weak selfin
    if let self = self {
        testMethod2()
    }
}

使用 swift 5.8 需要升级 Xcode 到 14.3 及以上

本文同步自微信公众号 “iOS新知”,每天准时分享一个新知识,这里只是同步,想要及时学到就来关注我吧!