我有一个CoreDataStore类,该类具有两个通用占位符,可用于模型中的每种实体类型。这个想法是,它从商店中获取NSManagedObject子类(基于一种通用类型),将其转换为适当的对象(基于另一种通用类型)并返回该对象。

此行为的目的是这样的,因此,我将核心数据方面保持封装状态,并避免在整个应用程序中传递NSManagedObject实例。

示例潜在用法

这纯粹是如何使用法看起来进一步证明我要达到的目的。

let personStore = CoreDataStore<ManagedPerson, Person>()
let personData = personStore.fetchSomeObject() // personData is a value type Person

我有以下代码,分成多个文件,但为简单起见,此处以修改后的方式显示。
import Foundation
import CoreData

// MARK: - Core Data protocol and managed object

protocol ManagedObjectProtocol { }

class ManagedPerson: NSManagedObject, ManagedObjectProtocol {
    var title: String?
}

class ManagedDepartment: NSManagedObject, ManagedObjectProtocol {
    var name: String?
}

// MARK: - Simple struct representations

protocol DataProtocol {
    typealias ManagedObjectType: ManagedObjectProtocol
    init(managedObject: ManagedObjectType)
}

struct Person {
    var title: String?
}

struct Department {
    var name: String?
}

extension Person: DataProtocol {
    typealias ManagedObjectType = ManagedPerson
    init(managedObject: ManagedPerson) {
        self.title = managedObject.title
    }
}

extension Department: DataProtocol {
    typealias ManagedObjectType = ManagedDepartment
    init(managedObject: ManagedDepartment) {
        self.name = managedObject.name
    }
}

class CoreDataStore<ManagedObject: ManagedObjectProtocol, DataObject: DataProtocol> {

    func fetchSomeObject() -> DataObject {
        var managedObject: ManagedObject // fetch an NSManagedObject

        // Error here
        return DataObject(managedObject: managedObject)
    }

}

我收到的错误是当我尝试初始化fetchSomeObject中的结构时:

无法使用类型为((managedObject:ManagedObject)'的参数列表来调用类型为'DataObject'的初始化程序

显然,编译器无法弄清楚DataObject(仅限于符合DataProtocol的类型)可以用ManagedObject(仅限于符合ManagedObjectProtocol的类型)初始化,尽管它已在DataProtocol中声明。

有什么方法可以实现此功能?另外,这是一种合理的方法还是我完全摆脱了这个障碍?

更新资料

经过一番挖掘后,看来Swift generics are invariant导致了我所遇到的问题。

最佳答案

再次考虑您的CoreDataStore,例如CoreDataStore<ManagedPerson, Department>没有任何意义。为什么不?因为Department是没有问题的DataProtocol,但是其对应的typealias ManagedObjectType不是ManagedPerson

您的代码无法编译的原因是相同的。在return DataObject(managedObject: managedObject)中,您不能从任意DataObject初始化ManagedObject,仅可接受DataObject.ManagedObjectType

因此,您需要的是类型约束,添加此where子句,您的代码应该可以工作:

class CoreDataStore<ManagedObject: ManagedObjectProtocol, DataObject: DataProtocol
    where DataObject.ManagedObjectType == ManagedObject>

关于ios - 以“通用”方式将NSManagedObjects转换为结构(Swift),我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/33218100/

10-10 11:07