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

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

问题描述

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



现在我通过核心数据栈设置在我的AppDelegate,我在视图控制器之间传递我的MOC。但是最好迁移到UIManagedDocument并创建一个共享实例,所以我不必一直通过MOC?还因为它的较新版本?

解决方案

UIManagedDocument (通常是文件)到iCloud。它只与核心数据相切。



核心数据设置通常在 AppDelegate 中完成,错了你在那里做什么。事实上,如果你使用Core Data创建一个新项目,这就是Xcode模板的作用。



你通常不需要传递 ManagedObjectContext 从viewcontroller到viewcontroller。最好创建一个单例数据访问层,它可以在应用程序的任何地方提供上下文。在某些情况下,您可能希望为viewcontroller设置一个私有MOC,但不是很常见。



以下是创建单例DataAccessLayer的代码:



DataAccessLayer.h



@interface DataAccessLayer:NSObject

//将数据模型保存到DB
- (void)saveContext;

//跨应用程序共享的DataAccessLayer单例实例
+(id)sharedInstance;
+(void)disposeInstance;
//返回应用程序的受管对象上下文。
//如果上下文不存在,则创建它并将
//绑定到应用程序的持久存储协调器。
+(NSManagedObjectContext *)context;
@end

DataAccessLayer.m

  #importDataAccessLayer.h

//单例实现的静态实例
static DataAccessLayer __strong * manager = nil;

//私有实例方法/属性
@interface DataAccessLayer()

//返回应用程序的受管对象上下文。
//如果上下文不存在,则创建它,并将
//绑定到应用程序的持久存储协调器。
@property(readonly,strong,nonatomic)NSManagedObjectContext * managedObjectContext;

//返回应用程序的管理对象模型。
//如果模型不存在,则从应用程序的模型创建。
@property(readonly,strong,nonatomic)NSManagedObjectModel * managedObjectModel;

//返回应用程序的持久存储协调器。
//如果协调器不存在,则创建它,并将应用程序的
//存储添加到其中。
@property(readonly,strong,nonatomic)NSPersistentStoreCoordinator * persistentStoreCoordinator;

//返回应用程序的Documents目录的URL。
- (NSURL *)applicationDocumentsDirectory;
@end


@implementation DataAccessLayer

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

//应用程序间共享的DataAccessLayer单例实例
+(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];
}

//将数据模型保存到DB
- (void)saveContext
{
NSError * error = nil;
NSManagedObjectContext * managedObjectContext = self.managedObjectContext;
if(managedObjectContext!= nil)
{
if([managedObjectContext hasChanges]&&![managedObjectContext save:& error])
{
/ /需要提出一个更好的错误管理在这里。
NSLog(@未解析的错误%@,%@,错误,[错误userInfo]);
abort();
}
}
}

//返回应用程序的受管对象上下文。
//如果上下文不存在,则创建它,并将
//绑定到应用程序的持久存储协调器。
- (NSManagedObjectContext *)managedObjectContext
{
if(__managedObjectContext!= nil)
return __managedObjectContext;

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

//返回应用程序的管理对象模型。
//如果模型不存在,则从
//应用程序的模型创建。
- (NSManagedObjectModel *)managedObjectModel
{
if(__managedObjectModel!= nil)
return __managedObjectModel;

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

//返回应用程序的持久存储协调器。
//如果协调器不存在,则创建它,并将
//应用程序的存储添加到其中。
- (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错误%@,%@,错误,[错误userInfo]);
abort();
}

return __persistentStoreCoordinator;
}

//返回应用程序的Documents目录的URL。
- (NSURL *)applicationDocumentsDirectory
{
return [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory
inDomains:NSUserDomainMask] lastObject];
}

@end

你可以使用:

  NSManagedObjectContext * context = [DataAccessLayer context]; 

此设计通常工作良好。 NSManagedObjectContext 是一个非常轻量级的对象,所以没有真正的性能惩罚保持它。然而,如果你需要在其他线程上做Core Data东西,那么设计需要改变一点。从 Apple的文档


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



使用线程限制,你不应该在线程之间传递被管理对象或
被管对象上下文。要从一个上下文中跨过线程边界传递一个管理对象
,您可以:




  • 传递其对象ID ),并在接收管理对象上下文中使用objectWithID:或existingObjectWithID:error:

  • 在接收上下文上执行提取。

  • 已保存
    ,您无法将新插入的托管对象的ID传递给另一个上下文。 li>


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天全站免登陆