Swift闭包使用[weak self]触发weak应用类型限制报错如何解决
报错触发原因
这个报错的核心原因是类的存储属性默认值的求值时机早于实例初始化完成的时机:
- 你当前给
myAction设置的闭包是存储属性的默认值,这个值会在类实例初始化过程的最开始就完成计算,此时实例还没有被完整创建,根本不存在可以捕获的ViewController实例对象。 - 此时你写的
[weak self]中的self不会被编译器识别为实例对象,而是会被匹配为ViewController类的元类型对应的构造方法,Swift的实例方法默认是柯里化的,构造方法的类型刚好就是报错里提到的(ViewController) -> () -> ViewController,这是一个函数类型,自然不支持用weak修饰,就触发了这个编译错误。
解决方案
下面是两种常用的修复方案:
方案1:使用懒加载属性
把myAction改为lazy属性,懒加载属性的初始化会推迟到第一次访问该属性时才执行,此时类实例已经完成初始化,能捕获到正确的实例self:
import UIKit class ViewController: UIViewController { // 增加lazy修饰符 lazy var myAction: ((Int, Bool) -> Void)? = { [weak self] int, bool in // 此处self为正常的ViewController实例 } }
方案2:延后闭包赋值时机
先只声明属性,不在定义时给默认值,等实例初始化完成后(比如在viewDidLoad等生命周期方法里)再给属性赋值:
import UIKit class ViewController: UIViewController { // 仅声明属性,不设置默认值 var myAction: ((Int, Bool) -> Void)? override func viewDidLoad() { super.viewDidLoad() // 实例初始化完成后再赋值闭包 myAction = { [weak self] int, bool in // 此处self为正常的ViewController实例 } } }
注意:使用lazy属性时,属性的初始化仅会在第一次访问时执行一次,且本身不保证线程安全,多线程场景下需要额外做并发控制。
内容的提问来源于stack exchange,提问作者ScottyBlades
相关产品推荐
相关产品推荐

