Swift init调用实例方法报self未初始化错误解决方法
报错原因
Swift 对类类型实行严格的两段式初始化校验:在类的所有存储属性完成初始赋值之前,不允许访问self调用实例方法、读取实例属性。
你的代码里虽然已经给nameOfClass、students、grades三个属性赋了初始值,但gpa和highestGrade两个存储属性还未赋值,整个实例尚未完成第一阶段的初始化,此时调用self.getGpa()、self.getHighestGrade()就会触发你看到的编译错误。
可行修复方案
你可以根据自己的业务场景选下面任意一种实现方式:
方案1:将gpa、highestGrade改为计算属性(推荐)
这种方式不需要在初始化阶段调用方法赋值,两个属性会根据当前的grades动态计算结果,后续如果修改grades数组,GPA和最高分也会自动同步,不会出现数据不一致的问题,同时还能避免空数组崩溃的隐患:
class Classroom{ var nameOfClass : String var students : [String] var grades : [Int] // 改为计算属性 var gpa : Double { guard !grades.isEmpty else { return 0 } let sum = grades.reduce(0, +) return Double(sum) / Double(grades.count) } var highestGrade : Int { // 空数组兜底,避免越界崩溃 guard !grades.isEmpty else { return 0 } return grades.max()! } init(nameOfClass : String, students : [String], grades : [Int]){ self.nameOfClass = nameOfClass self.students = students self.grades = grades // 不需要额外给gpa、highestGrade赋值 } }
方案2:将计算逻辑改为静态方法
静态方法不依赖实例self,初始化阶段可以直接调用,只需要把grades作为参数传入即可完成计算,不需要提前访问实例:
class Classroom{ var nameOfClass : String var students : [String] var grades : [Int] var gpa : Double var highestGrade : Int init(nameOfClass : String, students : [String], grades : [Int]){ self.nameOfClass = nameOfClass self.students = students self.grades = grades // 直接调用静态方法,不需要访问self self.gpa = Classroom.calculateGpa(grades: grades) self.highestGrade = Classroom.calculateHighestGrade(grades: grades) } static func calculateGpa(grades: [Int]) -> Double{ guard !grades.isEmpty else { return 0 } let sum = grades.reduce(0, +) return Double(sum) / Double(grades.count) } static func calculateHighestGrade(grades: [Int]) -> Int{ guard !grades.isEmpty else { return 0 } return grades.max()! } }
方案3:先给两个属性赋临时默认值,初始化完成后再调用方法赋值
如果你一定要保留实例方法的写法,可以先给gpa和highestGrade赋临时初始值,等所有存储属性都完成初始化、实例可用之后,再调用实例方法覆盖这两个属性的值:
class Classroom{ var nameOfClass : String var students : [String] var grades : [Int] var gpa : Double = 0 var highestGrade : Int = 0 init(nameOfClass : String, students : [String], grades : [Int]){ self.nameOfClass = nameOfClass self.students = students self.grades = grades // 所有存储属性已经有初始值,此时可以正常访问self self.gpa = self.getGpa() self.highestGrade = self.getHighestGrade() } func getGpa() -> Double{ guard !grades.isEmpty else { return 0 } let sum = grades.reduce(0, +) return Double(sum) / Double(grades.count) } func getHighestGrade() -> Int{ guard !grades.isEmpty else { return 0 } return grades.max()! } }
注意:你原来的
getHighestGrade方法直接访问grades[0],如果传入的grades是空数组会触发越界崩溃,上面的修复代码都加了空数组兜底逻辑。
内容的提问来源于stack exchange,提问作者randy pahang
相关产品推荐
相关产品推荐

