我根据这篇博客文章(Swift 中)设计了一个核心数据堆栈,其中我有两个NSManagedObjectContext
实例,一个主队列上下文(NSMainQueueConcurrencyType
)和一个私有队列上下文(NSPrivateQueueConcurrencyType
),其中主上下文的工作是处理与用户交互相关的所有事情(编辑,向用户呈现数据)和私有上下文的唯一工作是写入磁盘。
为了使管理堆栈尽可能简单,我集成了Magical Record、Overcoat和Mantle。我将所有这些分为两个类,一个 Core Data 单例堆栈(基于 Magical Record 构建)和一个网络管理器单例(构建在 Overcoat 之上,而后者又构建在 Mantle 之上)。
Core Data 堆栈如下所示:
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) Magical Record 具有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
实例中,因此我可以直接保存到 Private Queue Context(其唯一的工作就是写入磁盘)是有道理的
3)如果我不需要使用主队列上下文进行保存/编辑,它不会成为我用于获取的上下文NSManagedObjects
(鉴于私有队列的工作是写入磁盘和保存/编辑功能Mantle 的中间模型结构似乎使 Main Queue Context 过时了)?