5月27日 11:50

Swift 扩展 extension 能做什么?有什么限制?

扩展(extension)给已有类型添加新功能,不需要访问源码。能加计算属性、方法、初始化器、嵌套类型、协议遵循。不能加存储属性、不能重写已有方法、不能添加指定初始化器。

扩展最大的价值:给系统类型加业务方法。比如给 String 加 var isPhoneNumber: Bool,给 Int 加 var formatted: String,给 UIColor 加 convenience init(hex:)——代码组织更清晰,不用写工具类。

追问

扩展能添加存储属性吗?

不能。存储属性需要修改类型的内存布局,扩展没有这个权限。需要额外存储空间时,用关联对象(Objective-C 运行时的 objc_setAssociatedObject)或者用包装类型。纯 Swift 类型没法用关联对象,只能换设计——用字典存储额外数据,或者改用子类/包装 struct。

扩展和继承有什么区别?

扩展是"横向添加功能",不改变类型的继承关系;继承是"纵向派生子类",可以重写方法。扩展不能重写已有方法,继承可以。扩展适用于所有类型(struct/enum/protocol),继承只适用于 class。优先用扩展——更轻量,不引入继承链的复杂性。

协议扩展的默认实现是怎么工作的?

协议扩展可以为协议方法提供默认实现,遵循协议的类型如果不自己实现就用默认的。但如果类型通过另一个协议扩展也提供了实现,调用时选哪个取决于变量的静态类型——这就是"协议扩展派发"的坑。解决:把方法写在协议声明里(不是扩展里),这样走动态派发,运行时决定。

扩展里的私有成员对外可见吗?

Swift 4 之前,同一文件的多个扩展可以访问彼此的 private 成员。Swift 4 之后,扩展和类型定义在同一文件时也能访问 private 成员,但不同文件的扩展不行。fileprivate 始终对同文件可见。

写段代码

swift
// 给系统类型加计算属性 extension String { var isPhoneNumber: Bool { let regex = "^1[3-9]\\d{9}$" return range(of: regex, options: .regularExpression) != nil } } // 便利初始化器 extension UIColor { convenience init(hex: String) { let hex = hex.trimmingCharacters(in: .alphanumerics.inverted) var int: UInt64 = 0 Scanner(string: hex).scanHexInt64(&int) let r, g, b: UInt64 switch hex.count { case 6: (r, g, b) = (int >> 16, int >> 8 & 0xFF, int & 0xFF) default: (r, g, b) = (0, 0, 0) } self.init(red: Double(r)/255, green: Double(g)/255, blue: Double(b)/255, alpha: 1) } } // 协议默认实现 protocol Identifiable { var id: String { get } } extension Identifiable { var id: String { UUID().uuidString } }
标签:Swift