SwiftUI中函数返回Int设为变量触发初始化报错的解决方法
报错核心原因
这是Swift类/结构体初始化规则的硬性限制:实例属性的初始值,必须在self完全初始化完成、可以被正常访问之前就准备好。当你把var p = pval()写在类定义里作为实例属性时,pval是需要绑定实例才能调用的成员方法,此时self还没初始化完,根本没法调用实例方法,编译器就会抛出这个错误。
你之前直接打印p能正常运行,是因为你当时是把这段代码写在全局作用域、函数作用域里执行的,流程上已经走完了实例初始化,所以没有碰到这个限制。
具体修复方案
方案1:将pval()改为静态方法
从原pval()的实现逻辑看,方法内部没有用到任何当前实例的属性、也没有依赖实例状态,所有计算都基于系统当前日期做独立判断,完全没有必要做成实例方法。把它改成静态方法后,方法本身不再依赖self的状态,属性初始化阶段就可以正常调用,是最贴合这个场景的修复方式:
// 调整为静态方法,消除对实例上下文的依赖 static func pval() -> Int { var p = 1 let now = Date() let day1 = Date.parse("2021-03-23") let day2 = Date.parse("2021-04-23") let day3 = Date.parse("2021-05-23") let day4 = Date.parse("2021-06-23") if now > day1 && now < day2 { p = 2 } else if now > day2 && now < day3 { p = 3 } else if now > day3 && now < day4 { p = 4 } return p } // 此时在属性声明处直接调用就不会触发编译错误 var p = pval()
方案2:把属性赋值挪到初始化器中
如果必须保留pval的实例方法身份,就不要在属性声明的位置直接赋初始值。先把p声明成隐式解包的可选存储属性,等所有必要的存储属性都初始化完成、self可正常访问之后,在自定义初始化器里调用pval()给p赋值:
class YourBusinessClass { // 先声明属性,不在声明位置初始化 var p: Int! // 原封不动保留原有实例方法pval() func pval() -> Int { var p = 1 let now = Date() let day1 = Date.parse("2021-03-23") let day2 = Date.parse("2021-04-23") let day3 = Date.parse("2021-05-23") let day4 = Date.parse("2021-06-23") if now > day1 && now < day2 { p = 2 } else if now > day2 && now < day3 { p = 3 } else if now > day3 && now < day4 { p = 4 } return p } // 自定义初始化器,此时self已经可用,可以正常调用实例方法 init() { self.p = pval() } }
方案3:使用懒加载属性绑定返回值
如果不需要在实例创建完成的第一时间就计算p的值,希望等第一次访问p的时候再触发pval()的计算,就可以用lazy关键字修饰p属性,把pval()的调用放进懒加载闭包里。因为懒加载属性的初始化逻辑是在self完全就绪之后才执行的,完全符合编译规则:
class YourBusinessClass { // lazy修饰的属性,初始化逻辑会在第一次访问时执行,此时self已完全可用 lazy var p: Int = { return self.pval() }() // 保留原有实例方法pval() func pval() -> Int { var p = 1 let now = Date() let day1 = Date.parse("2021-03-23") let day2 = Date.parse("2021-04-23") let day3 = Date.parse("2021-05-23") let day4 = Date.parse("2021-06-23") if now > day1 && now < day2 { p = 2 } else if now > day2 && now < day3 { p = 3 } else if now > day3 && now < day4 { p = 4 } return p } }
额外逻辑提示:原pval()的日期判断用的是严格开区间,刚好落在分界日(比如2021-03-23、2021-04-23当天)的时间会不匹配任何分支,最终返回默认值1。如果需要覆盖边界场景,可以把判断条件调整为
now >= day1 && now < day2这类形式,保证日期判断的逻辑连续性。
内容的提问来源于stack exchange,提问作者Code Beast

