Является ли плохой практикой создание универсальной оболочки для моделей Core Data? - PullRequest
0 голосов
/ 29 августа 2018

Я изучаю 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()
    }
}

Насколько этот код соответствует принципам ООП (в частности, можно ли назвать этот протокол реализацией шаблона DAO)? Нужны ли такие обертки? Или Core Data подразумевает прямое использование моделей в коде?

Какие возможные проблемы могут выявить это в будущем?

Буду очень признателен за советы более опытных разработчиков iOS. Заранее спасибо.

1 Ответ

0 голосов
/ 30 августа 2018

Протокол может быть слишком большим для такого рода функций, так как основной целью протоколов по-прежнему остается полиморфизм. Вместо этого вы можете использовать общую структуру:

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)

ИМО, лучше передать намерение иметь Фасад поверх CoreData.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...