Упрощенный базовый стек данных с использованием Mantle, Overcoat и Magical Record в объединении

Я разработал основной стек данных на основе этого поста в блоге (в Swift), где у меня есть два NSManagedObjectContext экземпляры, контекст главной очереди (NSMainQueueConcurrencyType) и контекст частной очереди (NSPrivateQueueConcurrencyType) где основная задача контекста состоит в том, чтобы иметь дело со всеми вещами, связанными с взаимодействием пользователя (редактирование, представление данных пользователю), и единственная задача частного контекста - запись на диск.

Чтобы сделать управление стеком максимально простым, я интегрировал Magical Record, Overcoat и Mantle. Я разделил все это на два класса: одноэлементный стек Core Data (построенный на Magical Record) и одноэлементный менеджер сети (создан на Overcoat, который, в свою очередь, построен на Mantle).

Стек основных данных выглядит следующим образом:

import UIKit
import CoreData
import MagicalRecord

class CoreData: NSObject {

    enum StackType: Int {
        case Default, AutoMigrating, iCloud, inMemory
    }

    static let sharedStack = CoreData()
    private override init() {}

    var type: StackType = .Default

    func setupStackWithType(type: StackType, withName name: String = MagicalRecord.defaultStoreName()) {
        self.type = type
        switch self.type {
        case .Default:
            MagicalRecord.setupCoreDataStackWithStoreNamed(name)
        case .AutoMigrating:
            MagicalRecord.setupCoreDataStackWithAutoMigratingSqliteStoreNamed(name)
        case .iCloud:
            if let documentsPath = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true).first {
                let url = NSURL(fileURLWithPath: documentsPath)
                MagicalRecord.setupCoreDataStackWithiCloudContainer(name, localStoreAtURL: url)
            } else {
                print("Error: could not find documents directory")
            }
        case .inMemory:
            MagicalRecord.setupCoreDataStackWithInMemoryStore()
        }
    }

    func setupStackWithStoreName(storeName: String, automigrating: Bool = true) {
        if automigrating {
            MagicalRecord.setupCoreDataStackWithAutoMigratingSqliteStoreNamed(storeName)
        } else {
            MagicalRecord.setupAutoMigratingCoreDataStack()
        }
    }

    func saveWithBlock(block: (NSManagedObjectContext!) -> ()) {
        MagicalRecord.saveWithBlock(block, completion: {
            (success, error) in

        })
    }

    func cleanUp() {
        MagicalRecord.cleanUp()
    }

    var managedObjectContext: NSManagedObjectContext {
        return NSManagedObjectContext.MR_defaultContext()
    }
    var privateContext: NSManagedObjectContext {
       return NSManagedObjectContext.MR_rootSavingContext()
    }
    var coordinator: NSPersistentStoreCoordinator {
        return NSPersistentStoreCoordinator.MR_defaultStoreCoordinator()
    }

    var persistentStore: NSPersistentStore {
        return NSPersistentStore.MR_defaultPersistentStore()
    }
}

Мой сетевой менеджер выглядит так:

import UIKit
import Overcoat
import MTLManagedObjectAdapter

class NetworkManager: OVCManagedHTTPSessionManager {

    static let singleton = NetworkManager(baseURL: NSURL(string: Config.ServerBaseEndpoint), managedObjectContext: nil, sessionConfiguration: {
        let config = NSURLSessionConfiguration.defaultSessionConfiguration()
        config.timeoutIntervalForRequest = 15
        config.timeoutIntervalForResource = 15
        return config
    }())

    private override init(baseURL url: NSURL?, managedObjectContext context: NSManagedObjectContext?, sessionConfiguration configuration: NSURLSessionConfiguration?) {
        super.init(baseURL: url, managedObjectContext: context, sessionConfiguration: configuration)
        self.responseSerializer.acceptableContentTypes = ["text/html", "application/json", "application/xml", "image/png"]
        self.securityPolicy = AFSecurityPolicy(pinningMode: .None)
        self.securityPolicy.allowInvalidCertificates = true
    }

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
    }

    // MARK: - OVCHTTPSessionManager

    override class func modelClassesByResourcePath() -> [String: AnyClass] {
        return [Types.RestApi.Post.rawValue:Post.self, "\(Types.RestApi.Post.rawValue)/*": Post.self]
    }
 }

То, что я не могу полностью обдумать, - это 1) как эти два класса могут работать вместе и 2) в отношении основного стека данных, в каком контексте сохранять, что делать с каким контекстом и т. Д.

За NetworkManager.swift (который занимает NSManagedObjectContext для сохранения моделей)

В каком контексте я инициализирую менеджер? Я предполагаю, что если вы сделаете сетевой запрос и JSON преобразуется в промежуточный Mantle модели и оттуда в NSManagedObejct экземпляры, эти экземпляры должны быть сохранены прямо в контексте частной очереди, в этом случае полностью обходя контекст основной очереди.

Когда говорим о CoreData.swift:

1) Волшебная запись имеет saveWithBlock метод, который создает локальный контекст и распространяет его до корневого контекста (в данном случае корневым контекстом является контекст приватной очереди), но неясно, какую работу следует выполнить внутри блока.

В своей документации они приводят этот пример:

Person *person = ...;

[MagicalRecord saveWithBlock:^(NSManagedObjectContext *localContext){

  Person *localPerson = [person MR_inContext:localContext];
  localPerson.firstName = @"John";
  localPerson.lastName = @"Appleseed";

}];

где они создают Person объект за пределами блока сохранения, а затем заново создайте объект в локальном контексте, а затем отредактируйте его свойства. Однако в моем случае все Person объекты будут экземпляром MTLModel не NSManagedObject, Когда я создаю некоторый объект модели, поскольку он не является базовым объектом данных, он не будет вставлен в какой-либо контекст, пока я не использую MTLManagedObjectAdapter превратить модель в NSManagedObject пример.

Кажется, лучший способ сделать это - создать MTLModel экземпляр (ы), сделайте все необходимое для редактирования, а затем либо 1) внутри saveWithBlock вставить вновь созданные управляемые объекты прямо в локальный контекст и позволить ему распространяться вверх или 2) вставить объекты в контекст приватной очереди и сохранить.

2) Мне действительно нужно использовать контекст основной очереди вообще для сохранения и редактирования? Как я уже говорил, Mantle имеет классы моделей в качестве подкласса MTLModel а позже отображает их в NSManagedObject экземпляры, так что имеет смысл, что я мог бы просто сохранить непосредственно в контекст приватной очереди (чья единственная работа в любом случае заключается в записи на диск)

3) Если мне не нужно использовать контекст основной очереди для сохранения / редактирования, не станет ли он контекстом, который я использую для извлечения NSManagedObjects (учитывая, что работа Частной очереди заключается в записи на диск, а функции сохранения / редактирования контекста главной очереди, похоже, устарели из-за промежуточной структуры модели Mantle)?

0 ответов

Другие вопросы по тегам