UIView的appearance()代理工作原理及自定义UIView的UIAppearance实现问题
问题原因
- UIAppearance 是基于 Objective-C runtime 的消息转发机制实现的,只有暴露给 OC runtime 且开启动态分发的属性才能被 UIAppearance 识别调用。
- 你当前定义的
TestView以及它的testColor属性都是纯 Swift 实现,没有标记 OC 可见,也没有开启动态分发,当 UIAppearance 实例调用testColor的 setter 方法时就会触发方法未识别的崩溃。
修复方法
给自定义类和要支持外观配置的属性添加 @objc 和 dynamic 修饰即可:
// 给自定义类添加 @objc 标记,暴露给 OC 运行时 @objc final class TestView: UIView { // 给要支持 UIAppearance 的属性添加 @objc dynamic 修饰,开启 OC 动态分发 @objc dynamic var testColor: UIColor = .white { didSet { backgroundColor = testColor } } }
修改后原控制器代码无需改动,运行3秒后两个 TestView 都会自动变为红色,符合预期。
自定义 UIView 实现 UIAppearance 的通用规则
- 所有要支持 UIAppearance 的属性必须添加
@objc dynamic修饰符 - Swift 定义的自定义 UIView 子类需要添加
@objc标记,暴露给 OC 运行时 - 支持 UIAppearance 的属性类型必须是可桥接到 OC 的类型:基础数值类型(CGFloat、Int 等)、UIKit 类、继承自 NSObject 的自定义类都可以,纯 Swift 类型(Struct、非桥接 Enum 等)不支持
- 带参数的外观配置方法同样需要添加
@objc修饰,示例:
@objc func setTestColor(_ color: UIColor, for state: UIControl.State) { // 内部逻辑实现 }
内容的提问来源于stack exchange,提问作者Dannis Case
相关产品推荐
相关产品推荐

