Swift中ReferenceWritableKeyPath转字符串失败,Release模式返回指针如何解决?
Realm KeyPath转字符串在Release模式下失效的问题与解决过程
场景与问题
我有一个继承自Realm Object的Product类:
@objc class Product: Object { @Persisted(primaryKey: true) var id: String = "" @Persisted var externalId: String? @Persisted var name: String? }
我尝试实现一个通用的对象更新方法,接收包含KeyPath和对应值的字典,通过Realm的setValue(_:forKey:)方法更新对象:
func setValue(_ value: Any?, forKey key: String)
为此我编写了KeyPath的扩展,用来获取它的字符串表示:
fileprivate extension KeyPath { var asString: String { let wholeString = String(describing: self) let dropLeading = "\\" + String(describing: Root.self) + "." let keyPathString = "\(wholeString.dropFirst(dropLeading.count))" return keyPathString } }
这个实现在Debug模式下完全正常,但切换到Release scheme构建应用时,返回的不是Product.name这类预期值,而是类似\Product.<computed 0x000000010c51ed18 (Bool)>的内容,导致调用setValue时应用直接崩溃。
初衷与尝试
我的核心目标是封装Realm操作,最初的更新方法设计如下:
func updateObjects<DBEntity: Object, KeyPathType: NSObject, T>( ofType objectType: DBEntity.Type, where query: ((Query<DBEntity>) -> Query<Bool>)? = nil, with keyedValues: [KeyPath<KeyPathType, T>: T], completion: (Error?) -> Void? )
使用KeyPath而非字符串的核心原因是减少错误,避免因属性名称变更导致崩溃,因此将keyedValues参数改为[String: T]并非可行方案。
后来发现Swift的KeyPath并不保证能转换为人类可读的字符串,这条实现路径根本走不通。
最终解决方案
我将更新方法修改为以下形式:
func updateObjects<DBEntity: Object>( ofType objectType: DBEntity.Type, where query: ((Query<DBEntity>) -> Query<Bool>)? = nil, updateBlock: @escaping ([DBEntity]) -> Void, completion: DBOperationCompletion? )
现在直接在updateBlock内部完成对象属性的更新操作即可。
内容的提问来源于stack exchange,提问作者Alex Sh.
相关产品推荐
相关产品推荐

