Swift的 convenience && designated init
在 OC 中 init 方法是非常不安全的,没人能够保证 init 只被调用一次,也没有人保证在初始化方法调用以后实例的各个变量都完成初始化,甚至如果在初始化里使用属性进行设置的的话,还可能会造成各种问题。Swift 强化了 designated 初始化方法的地位。swift 中不加修饰的 init 方法都需要在方法中保证所有非 Optional 得实例变量被赋值初始化,而在子类中也强制(显示或隐式的)调用 super 版本的 designated 初始化,所以无论怎样被初始化的对象总是可以完成完整的初始化的。 class ClassA { let numA: Int // 不加修饰的 init 方法都需要在方法中保证所有非 Optional 得实例变量被赋值初始化 init(num: Int) { numA = num } } class ClassB: ClassA { let numB: Int override init(num: Int) { numB = num + 1 // 在 init 里我们可以对 let 的实例常量进行赋值,这是初始化方法的重要特点。正常情况下 let 声明的值是不可变的,无法被赋值,这对构建线程安全的 API 十分有用。而 init 只可能被调用一次,所以在 init 里我们可以为不变量进行赋值,而不会引起任何线程安全的问题 super.init(num: num) } } 与 designated 初始化方法啊对应的是在 init 前加上 convenience 关键字的初始化方法。这类方法只作为补充和提供使用上的方便。所有的 convenience 初始化方法都必须调用同一个类中的 designated 初始化完成设置,另外 convenience 的初始化方法是不能被子类重写或者是从子类中以 super 的方式被调用的。 class ClassAA { let numA: Int init(num: Int) { numA = num } convenience init(bigNum: Bool) { self.init(num: bigNum ? 10000 : 1) // 所有的 convenience 初始化方法都必须调用同一个类中的 designated 初始化完成设置 } } class ClassBB: ClassAA { let numB: Int override init(num: Int) { numB = num + 1 super.init(num: num) } } 只要在子类中实现重写了父类 convenience 方法所需要的 init 方法的话,我们在子类中就可以使用父类的 convenience 初始化方法了。比如上面我们即使在 ClassBB 中没有 bigNum 版本的 convenience init(bigNum: Bool),我们仍然是可以是用这个方法来完成子类初始化的: let anObj = ClassBB(bigNum: true) print(anObj.numA, anObj.numB) 输出:10000和10001 总结:初始化方法永远遵循以下两个原则 1.初始化路径必须保证对象完全初始化,这可以通过调用本类型的 designated 初始化方法得到保证; 2.子类的 designated 初始化方法必须调用父类的 designated 方法,以保证父类也完成初始化。 对于某些我们希望子类中一定实现的 designated 初始化方法,我们可以通过添加 required 关键字进行限制,强制子类对这个方法重写实现。这样做的最大的好处是可以保证依赖于某个 designated 初始化方法的 convenience 一直可以被使用。 下面的代码中如果希望初始化方法对于子类一定可用,就将 init(num: Int) 声明为必须。 复制代码 class ClassAAA { let numA: Int required init(num: Int) { numA = num } required convenience init(bigNum: Bool) { self.init(num: bigNum ? 10000 : 1) } } class ClassBBB: ClassAAA { let numB: Int required init(num: Int) { numB = num + 1 super.init(num: num) } } let sencondObj = ClassBB(bigNum: true) print(sencondObj.numA, sencondObj.numB) 输出:10000和10001 对于 convenience 的初始化方法也可以加上 required 以确保子类对其进行实现。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
2015-07-24 Android事件模型之interceptTouchEvnet ,onTouchEvent关系正解
2015-07-24 android事件传递机制以及onInterceptTouchEvent()和onTouchEvent()详解二之小秘与领导的故事
2015-07-24 Android中如何实现多行、水平滚动的分页的Gridview?
2014-07-24 In-Cell、On-Cell和OGS全贴合屏幕技术区别
2014-07-24 android不自动弹出虚拟键盘