Swift类初始化时传递self作为参数触发报错如何解决?
报错原因
Swift 遵循严格的两段式初始化规则:
- 第一阶段必须完成当前类所有存储属性的赋值,之后
self才会被允许访问使用 - 你当前的代码中
feeds是let常量,属于必须在初始化第一阶段赋值的存储属性,赋值时需要传入self,但此时self还未完成所有属性的初始化,因此触发编译报错 - 额外注意:原代码中两个类互相强持有,会出现循环引用导致内存泄漏,必须调整其中一方的引用类型
解决方案
推荐两种常用落地方式,均可满足需求:
方案1:使用lazy属性(最简便)
将User的feeds属性声明为lazy,lazy属性的初始化会延迟到该属性第一次被访问时执行,此时User实例已经完成全部初始化,self可以正常使用。同时将FeedManager的user属性声明为unowned避免循环引用。
修改后的代码如下:
class User: Identifiable, Equatable { let id = UUID() // 改成lazy var,初始化在self可用后执行 lazy var feeds: FeedManager = FeedManager(user: self) var username: String var firstname: String var lastname: String var fullname: String var bio: String init(username: String, firstname: String, lastname: String, fullname: String, bio: String) { self.username = username self.lastname = lastname self.firstname = firstname self.fullname = firstname + " " + lastname self.bio = bio // 不需要再在这里给feeds赋值 } static func == (user1: User, user2: User) -> Bool { return user1.id == user2.id } } class FeedManager { // 改成unowned,避免循环引用 unowned let user: User var currentInvit: [PostData] = [] var currentHost: [PostData] = [] var currentAttend: [PostData] = [] var currentDismissed: [PostData] = [] var pastHost: [PostData] = [] var pastAttend: [PostData] = [] init(user: User) { self.user = user } }
方案2:使用隐式解包可选类型
如果你希望feeds的赋值逻辑放在init方法内,可以将其声明为隐式解包可选类型,同样可以满足规则要求:
class User: Identifiable, Equatable { let id = UUID() // 声明为隐式解包可选 var feeds: FeedManager! var username: String var firstname: String var lastname: String var fullname: String var bio: String init(username: String, firstname: String, lastname: String, fullname: String, bio: String) { self.username = username self.lastname = lastname self.firstname = firstname self.fullname = firstname + " " + lastname self.bio = bio // 此时所有存储属性已经赋值完成,self可以正常使用 self.feeds = FeedManager(user: self) } static func == (user1: User, user2: User) -> Bool { return user1.id == user2.id } } // FeedManager的user同样要加unowned,和方案1一致
方案选择建议
- 无特殊需求优先选方案1,代码更简洁,不需要手动在init里赋值
- 如果你需要在初始化阶段传入不同的FeedManager配置参数,再选择方案2
内容的提问来源于stack exchange,提问作者John Sorensen
相关产品推荐
相关产品推荐

