【问题标题】:Is it a bad practice to create a generic wrapper over Core Data models?在 Core Data 模型上创建通用包装器是一种不好的做法吗?
【发布时间】:2018-08-28 23:56:06
【问题描述】:

我正在研究 Swift 和 Core Data,我计划在我的模型上使用一个简单的包装器。

此时,协议和扩展如下所示:

protocol CRUD {
    associatedtype T: NSManagedObject

    var context: NSManagedObjectContext { get }

    var items: [T]! { get set }

    func getAll() -> [T]
    mutating func addOrUpdate(_ item: T) -> T
    mutating func delete(_ item: T)
}


extension CRUD where T: NSManagedObject {
    var context: NSManagedObjectContext {
        return (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
    }

    func save() {
        do {
            try context.save()
        } catch {
            fatalError("Saving of \(String(describing: self)) failed")
        }
    }

    func getAll() -> [T] {
        let fetchRequest = NSFetchRequest<T>(entityName: String(describing: T.self))
        let list: [T]

        do {
            list = try context.fetch(fetchRequest)
        } catch {
            fatalError("Fetching of \(String(describing: self)) failed")
        }

        return list
    }

    mutating func delete(_ item: T) {
        if let index = items.index(of: item) {
            items.remove(at: index)
        }

        context.delete(item)
        save()
    }

    mutating func addOrUpdate(_ item: T) -> T {
        if (items.contains(item)) {
            items.append(item)
        }

        save()
        return item
    }
}

每个模型都是这样声明的:

class TaskModel : CRUD {
    typealias T = Task

    var items: [Task]! 

    init() {
        self.items = getAll()
    }
}

这段代码与OOP的原理有多少对应(特别是,我可以称这个协议为DAO模式的实现)吗?需要这样的包装吗?或者Core Data是否暗示在代码中直接使用模型?

未来可能会出现哪些问题?

我将非常感谢更有经验的 iOS 开发人员的建议。提前谢谢你。

【问题讨论】:

    标签: ios swift oop generics core-data


    【解决方案1】:

    对于这种功能来说,协议可能太多了,因为协议的主要目标仍然是多态性。您可以改用通用结构:

    struct CRUD<T: NSManagedObject> {
    
        var context: NSManagedObjectContext {
            return (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
        }
    
        var items = [T]()
    
        // let's provide two approaches for initialization
        init() {
            self.init(items: getAll())
        }
    
        init(items: [T]) {
            self.items = items
        }
    
        func save() {
            do {
                try context.save()
            } catch {
                fatalError("Saving of \(String(describing: self)) failed")
            }
        }
    
        func getAll() -> [T] {
            let fetchRequest = NSFetchRequest<T>(entityName: String(describing: T.self))
            let list: [T]
    
            do {
                list = try context.fetch(fetchRequest)
            } catch {
                fatalError("Fetching of \(String(describing: self)) failed")
            }
    
            return list
        }
    
        mutating func delete(_ item: T) {
            if let index = items.index(of: item) {
                items.remove(at: index)
            }
    
            context.delete(item)
            save()
        }
    
        mutating func addOrUpdate(_ item: T) -> T {
            if (items.contains(item)) {
                items.append(item)
            }
    
            save()
            return item
        }
    }
    

    然后你可以在你的课堂上使用它:

    class TaskModel {
        // making sure no-one from outside can mutate our CRUD
        private(set) lazy var crud = CRUD<Task>()
    
        init() {
            // nothing to do here, the items are already populated
        }
    }
    
    let model = TaskModel()
    // the following won't compile
    model.crud.delete(someTask)
    

    IMO,这更好地传达了在 CoreData 上拥有 Facade 的意图。

    【讨论】:

      猜你喜欢
      • 2011-04-24
      • 2023-03-04
      • 2015-10-01
      • 2011-12-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多