NSFetchedResultsController子类调用object(at:)类型报错如何解决
NSFetchedResultsController的object(at:)方法默认返回值为遵守NSFetchRequestResult协议的泛型类型。你接入的RichFetchedResultsController子类未明确指定返回的托管对象类型,且你之前重写的object(at:)完全沿用了父类的NSFetchRequestResult返回值,编译器无法识别该返回值对应的自定义NSManagedObject子类,因此抛出value of type 'NSFetchRequestResult' has no member 'RelationshipEntityProperty'编译错误。
你之前的重写操作没有修改返回值的类型信息,等价于直接调用父类方法,自然无法解决问题。
根据项目实际场景选择以下任意一种方案即可:
方案1:固定返回单一实体类型(适配子类仅服务于单个实体的场景)
修改重写的object(at:)方法,将返回值替换为业务中实际使用的NSManagedObject子类,内部做强制类型转换即可。Swift支持子类重写方法时返回父类返回值的子类型(协变返回特性),不会有语法问题:// 将YourEntityClass替换为你项目中对应的实体类名 public override func object(at indexPath: IndexPath) -> YourEntityClass { super.object(at: indexPath) as! YourEntityClass }改完后所有原有调用
object(at:)的位置都会自动识别为对应实体类型,不需要修改现有业务代码。方案2:泛型兼容多实体(适配子类需要服务于多个不同实体的场景)
给RichFetchedResultsController增加泛型约束,对齐父类的泛型设计,重写方法时返回泛型指定的类型:// 子类声明增加泛型参数,约束为遵守NSFetchRequestResult协议的类型 class RichFetchedResultsController<ResultType: NSFetchRequestResult>: NSFetchedResultsController<ResultType> { public override func object(at indexPath: IndexPath) -> ResultType { super.object(at: indexPath) } }后续初始化FRC时明确指定绑定的实体类型即可,例如
RichFetchedResultsController<YourEntityClass>(...),编译器会自动推导object(at:)的返回值类型。方案3:调用侧临时强转(适配不方便修改子类源码的场景)
如果无法修改RichFetchedResultsController的源码,直接在调用object(at:)的位置手动做类型强转即可:let randomEntity = (fetchedResultsController.object(at: indexPath) as! YourEntityClass).relationshipEntity
上述方案中用到的as!强制类型转换的安全性和原生NSFetchedResultsController的使用逻辑一致,只要保证fetchRequest绑定的实体和强转目标类型匹配,就不会触发运行时崩溃。
内容的提问来源于stack exchange,提问作者user10711707

