核心数据:UIManagedDocument 或 AppDelegate 设置核心数据堆栈? [英] Core Data: UIManagedDocument or AppDelegate to setup core data stack?

查看:35
本文介绍了核心数据:UIManagedDocument 或 AppDelegate 设置核心数据堆栈?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我对在哪里设置我的核心数据堆栈有点困惑.在 Appdelegate 中或使用 UIManagedDocument 的共享实例,描述如下?:http://adevelopingstory.com/blog/2012/03/core-data-with-a-single-shared-uimanageddocument.html

现在,我在 AppDelegate 中设置了核心数据堆栈,并且正在视图控制器之间传递我的 MOC.但是迁移到 UIManagedDocument 并创建一个共享实例会更好,这样我就不必一直传递 MOC 了吗?还因为它更新?

解决方案

UIManagedDocument 用于将数据(通常是文件)同步到 iCloud.它只是与核心数据无关.

Core Data 设置通常在 AppDelegate 中完成,因此您在那里所做的没有任何问题.事实上,如果您使用 Core Data 创建一个新项目,Xcode 模板就是这样做的.

您通常不需要将 ManagedObjectContext 从 viewcontroller 传递到 viewcontroller.最好创建一个可以在应用程序的任何位置提供上下文的单例数据访问层.在某些情况下,您可能希望为视图控制器使用私有 MOC,但并不经常这样做.

下面是一些创建单例 DataAccessLayer 的代码:

DataAccessLayer.h

@interface DataAccessLayer : NSObject//将数据模型保存到数据库中- (void)saveContext;//DataAccessLayer单例实例跨应用共享+ (id) 共享实例;+ (void)disposeInstance;//返回应用程序的托管对象上下文.//如果上下文不存在,则创建并绑定//到应用程序的持久存储协调器.+ (NSManagedObjectContext *)上下文;@结尾

DataAccessLayer.m

#import "DataAccessLayer.h"//单例实现的静态实例静态 DataAccessLayer __strong *manager = nil;//私有实例方法/属性@interface 数据访问层 ()//返回应用程序的托管对象上下文.//如果上下文不存在,则创建它并//绑定到应用程序的持久存储协调器.@property (只读、强、非原子) NSManagedObjectContext *managedObjectContext;//返回应用程序的托管对象模型.//如果模型尚不存在,则从应用程序的模型中创建.@property (只读,强,非原子) NSManagedObjectModel *managedObjectModel;//返回应用程序的持久存储协调器.//如果协调器不存在,则创建它并应用程序的//商店添加到它.@property (readonly,strong,nonatomic) NSPersistentStoreCoordinator *persistentStoreCoordinator;//返回应用程序 Documents 目录的 URL.- (NSURL *)applicationDocumentsDirectory;@结尾@implementation DataAccessLayer@synthesize managedObjectContext = __managedObjectContext;@synthesize managedObjectModel = __managedObjectModel;@synthesize persistentStoreCoordinator = __persistentStoreCoordinator;//DataAccessLayer单例实例跨应用共享+ (id)sharedInstance{@同步(自我){如果(经理 == 无)manager = [[self alloc] init];}退货经理;}+ (void)disposeInstance{@同步(自我){经理=无;}}+(NSManagedObjectContext *)上下文{返回 [[DataAccessLayer sharedInstance] managedObjectContext];}//将数据模型保存到数据库中- (void)saveContext{NSError *error = nil;NSManagedObjectContext *managedObjectContext = self.managedObjectContext;if (managedObjectContext != nil){if ([managedObjectContext hasChanges] && ![managedObjectContext save:&error]){//需要在这里提出更好的错误管理.NSLog(@"未解决的错误 %@, %@", error, [error userInfo]);中止();}}}//返回应用程序的托管对象上下文.//如果上下文不存在,则创建它并//绑定到应用程序的持久存储协调器.- (NSManagedObjectContext *)managedObjectContext{if (__managedObjectContext != nil)返回 __managedObjectContext;NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];如果(协调员!= nil){__managedObjectContext = [[NSManagedObjectContext alloc] init];[__managedObjectContext setPersistentStoreCoordinator:coordinator];}返回 __managedObjectContext;}//返回应用程序的托管对象模型.//如果模型不存在,则从//应用程序的模型.- (NSManagedObjectModel *)managedObjectModel{if (__managedObjectModel != nil)返回 __managedObjectModel;NSURL *modelURL = [[NSBundle mainBundle] URLForResource:@"Model"withExtension:@"momd"];__managedObjectModel = [[NSManagedObjectModel 分配]initWithContentsOfURL:modelURL];返回 __managedObjectModel;}//返回应用程序的持久存储协调器.//如果协调器不存在,则创建它并//应用程序的商店添加到它.- (NSPersistentStoreCoordinator *)persistentStoreCoordinator{if (__persistentStoreCoordinator != nil)返回 __persistentStoreCoordinator;NSURL *storeURL = [[self applicationDocumentsDirectory]URLByAppendingPathComponent:@"MyData.sqlite"];NSError *error = nil;__persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc]initWithManagedObjectModel:[self managedObjectModel]];if (![__persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType配置:nil URL:storeURL 选项:nil 错误:&error]){NSLog(@"未解决的错误 %@, %@", error, [error userInfo]);中止();}返回 __persistentStoreCoordinator;}//返回应用程序 Documents 目录的 URL.- (NSURL *)applicationDocumentsDirectory{返回 [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectoryinDomains:NSUserDomainMask] lastObject];}@结尾

任何时候你需要上下文,你可以使用:

NSManagedObjectContext *context = [DataAccessLayer 上下文];

这种设计通常效果很好.NSManagedObjectContext 是一个非常轻量级的对象,因此保留它并没有真正的性能损失.但是,如果您需要在其他线程上执行 Core Data 的工作,则需要对设计进行一些更改.来自 Apple 的文档:p><块引用>

您必须在将要运行的线程上创建托管上下文用过的.如果你使用 NSOperation,注意它的 init 方法是在与调用者相同的线程.因此,您不得创建队列的 init 方法中队列的托管对象上下文,否则它与调用者的线程相关联.相反,你应该在 main(对于串行队列)或 start(对于并发队列).

使用线程限制,您不应传递托管对象或线程之间的托管对象上下文.传递"托管对象从一个上下文跨线程边界到另一个上下文,您可以:

  • 传递其对象 ID (objectID) 并使用 objectWithID: 或 existingObjectWithID:error:在接收托管对象上下文上.对应的托管对象必须有已保存 - 您不能将新插入的托管对象的 ID 传递给另一个上下文.
  • 在接收上下文中执行提取.

I am a little confused about where to setup my Core data Stack. In the Appdelegate or using a shared instance of UIManagedDocument, described here?: http://adevelopingstory.com/blog/2012/03/core-data-with-a-single-shared-uimanageddocument.html

Right now I have by core data stack setup in my AppDelegate and I am passing my MOC around between the viewcontrollers. But would it be better to migrate to UIManagedDocument and make a shared Instance, so I don't have to pass the MOC around all the time? And also because its newer?

解决方案

UIManagedDocument is used to sync data (typically files) to iCloud. It is only tangentially related to Core Data.

Core Data setup is typically done in the AppDelegate so there is nothing wrong with what you are doing there. In fact, if you create a new project using Core Data that is how the Xcode template will do it.

You usually do not need to pass your ManagedObjectContext around from viewcontroller to viewcontroller. It is better to create a singleton Data Access layer which can provide context anywhere in your app. There are some cases where you might want to have a private MOC for a viewcontroller, but not very often.

Here's some code to create a singleton DataAccessLayer:

DataAccessLayer.h

@interface DataAccessLayer : NSObject

   //Saves the Data Model onto the DB
   - (void)saveContext;

   //DataAccessLayer singleton instance shared across application
   + (id) sharedInstance;
   + (void)disposeInstance;
   // Returns the managed object context for the application.
   // If the context doesn't already exist, it is created and bound 
   // to the persistent store coordinator for the application.
   + (NSManagedObjectContext *)context;
@end

DataAccessLayer.m

#import "DataAccessLayer.h"

//static instance for singleton implementation
static DataAccessLayer __strong *manager = nil;

//Private instance methods/properties
@interface DataAccessLayer ()

// Returns the managed object context for the application.
// If the context doesn't already exist, it is created and 
// bound to the persistent store coordinator for the application.
@property (readonly, strong, nonatomic) NSManagedObjectContext *managedObjectContext;

// Returns the managed object model for the application.
// If the model doesn't already exist, it is created from the application's model.
@property (readonly, strong, nonatomic) NSManagedObjectModel *managedObjectModel;

// Returns the persistent store coordinator for the application.
// If the coordinator doesn't already exist, it is created and the application's 
// store added to it.
@property (readonly,strong,nonatomic) NSPersistentStoreCoordinator *persistentStoreCoordinator;

// Returns the URL to the application's Documents directory.
- (NSURL *)applicationDocumentsDirectory;
@end


@implementation DataAccessLayer

@synthesize managedObjectContext = __managedObjectContext;
@synthesize managedObjectModel = __managedObjectModel;
@synthesize persistentStoreCoordinator = __persistentStoreCoordinator;

//DataAccessLayer singleton instance shared across application
+ (id)sharedInstance
{
    @synchronized(self) 
    {
        if (manager == nil)
            manager = [[self alloc] init];
    }
    return manager;
}

+ (void)disposeInstance
{
    @synchronized(self)
    {
        manager = nil;
    }
}

+(NSManagedObjectContext *)context
{
    return [[DataAccessLayer sharedInstance] managedObjectContext];
}

//Saves the Data Model onto the DB
- (void)saveContext
{
    NSError *error = nil;
    NSManagedObjectContext *managedObjectContext = self.managedObjectContext;
    if (managedObjectContext != nil) 
    {
        if ([managedObjectContext hasChanges] && ![managedObjectContext save:&error]) 
        {
            //Need to come up with a better error management here.
            NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
            abort();
        } 
    }
}

// Returns the managed object context for the application.
// If the context doesn't already exist, it is created and 
// bound to the persistent store coordinator for the application.
- (NSManagedObjectContext *)managedObjectContext
{
    if (__managedObjectContext != nil)
        return __managedObjectContext;

    NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
    if (coordinator != nil) 
    {
        __managedObjectContext = [[NSManagedObjectContext alloc] init];
        [__managedObjectContext setPersistentStoreCoordinator:coordinator];
    }
    return __managedObjectContext;
}

// Returns the managed object model for the application.
// If the model doesn't already exist, it is created from the 
// application's model.
- (NSManagedObjectModel *)managedObjectModel
{
    if (__managedObjectModel != nil) 
        return __managedObjectModel;

    NSURL *modelURL = [[NSBundle mainBundle] URLForResource:@"Model" 
                                               withExtension:@"momd"];
    __managedObjectModel = [[NSManagedObjectModel alloc] 
                         initWithContentsOfURL:modelURL];
    return __managedObjectModel;
}

// Returns the persistent store coordinator for the application.
// If the coordinator doesn't already exist, it is created and the 
// application's store added to it.
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator
{
    if (__persistentStoreCoordinator != nil) 
        return __persistentStoreCoordinator;

    NSURL *storeURL = [[self applicationDocumentsDirectory] 
                         URLByAppendingPathComponent:@"MyData.sqlite"];

    NSError *error = nil;
    __persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc]
                                     initWithManagedObjectModel:[self managedObjectModel]];

    if (![__persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType
                           configuration:nil URL:storeURL options:nil error:&error]) 
    {
        NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
        abort();
    }    

    return __persistentStoreCoordinator;
}

// Returns the URL to the application's Documents directory.
- (NSURL *)applicationDocumentsDirectory
{
    return [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory
                                         inDomains:NSUserDomainMask] lastObject];
}

@end

Any time you need context, you can grab it using:

NSManagedObjectContext *context = [DataAccessLayer context];

This design generally works well. NSManagedObjectContext is a very lightweight object, so there isn't a real performance penalty keeping it around. However, if you need to do Core Data stuff on other threads, the design needs to change a bit. From Apple's docs:

You must create the managed context on the thread on which it will be used. If you use NSOperation, note that its init method is invoked on the same thread as the caller. You must not, therefore, create a managed object context for the queue in the queue’s init method, otherwise it is associated with the caller’s thread. Instead, you should create the context in main (for a serial queue) or start (for a concurrent queue).

Using thread confinement, you should not pass managed objects or managed object contexts between threads. To "pass" a managed object from one context another across thread boundaries, you either:

  • Pass its object ID (objectID) and use objectWithID: or existingObjectWithID:error: on the receiving managed object context. The corresponding managed objects must have been saved—you cannot pass the ID of a newly-inserted managed object to another context.
  • Execute a fetch on the receiving context.

这篇关于核心数据:UIManagedDocument 或 AppDelegate 设置核心数据堆栈?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆