NSKeyValueCoding.setValue(_:forKey:)在Swift项目中调用报错无效应如何解决
问题1:当前测试示例崩溃的解决方案
崩溃的根本原因是KVC(键值编码)是Objective-C runtime的特性,Swift 4及之后版本默认不会将Swift原生声明的属性自动暴露给Objective-C runtime,所以你在继承自NSObject的Swift类中声明的txt属性无法被KVC识别,才会抛出not key value coding-compliant异常。
只需要给需要通过KVC访问的属性添加@objc修饰符即可解决,修改后的MyClass代码如下:
class MyClass: NSObject { // 加@objc暴露给ObjC runtime,支持KVC访问 @objc var txt :String = "" var useSetVal :Bool = false func update(){ if(useSetVal){ setValue("used set val", forKey: "txt") } else { txt = "used =" } useSetVal = !useSetVal } }
修改后运行项目,点击按钮即可正常在两个文本之间切换。
问题2:旧项目setValue失效+动画失效的根因与解决方案
你手上2017年的旧项目大概率是基于Swift 3及更早版本开发的,早期Swift版本会默认将继承自NSObject的类的所有属性自动暴露给Objective-C runtime,所以当时的KVC、CABasicAnimation调用都能正常运行。后续Xcode升级后默认使用Swift 4+版本编译,隐式暴露ObjC的规则被关闭,就会出现属性无法被KVC、CoreAnimation识别的问题,表现为setValue调用无效果、动画失效。
可以按优先级选择两种解决方案:
- 方案1:精准适配,给所有需要通过KVC访问、或者作为CoreAnimation动画keyPath的属性单独添加
@objc修饰符 - 方案2:如果整个类的属性都需要和ObjC交互,直接给类添加
@objcMembers修饰符,类内所有属性会自动暴露给ObjC runtime,不用逐个加@objc
最小可复现示例制作规范
你当前提供的SwiftUI测试示例已经符合最小可复现要求:只保留触发问题的核心代码、无冗余业务逻辑、其他开发者复制代码到本地可以直接运行复现问题。
如果你需要制作适配旧UIKit项目的最小复现示例,不需要用Storyboard,纯代码编写UI更简单:
- 新建iOS项目时选择
UIKit模板,语言选Swift - 删掉项目里的Main.storyboard文件,在info.plist里删掉Main相关的配置项
- 直接在AppDelegate(或SceneDelegate)里手动创建UIWindow,设置rootViewController为自定义的ViewController
- 在ViewController里手动添加按钮、写触发逻辑即可,全程不需要拖拽界面操作。
内容的提问来源于stack exchange,提问作者Ben Jasperson
相关产品推荐
相关产品推荐

