5

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

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

4

2 回答 2

6

UIManagedDocument用于将数据(通常是文件)同步到 iCloud。它仅与核心数据相干。

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

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

下面是一些创建单例 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

数据访问层.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

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

NSManagedObjectContext *context = [DataAccessLayer context];

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

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

使用线程限制,您不应在线程之间传递托管对象或托管对象上下文。要跨线程边界从一个上下文“传递”另一个托管对象,您可以:

  • 传递其对象 ID (objectID) 并在接收托管对象上下文中使用 objectWithID: 或 existingObjectWithID:error:。必须保存相应的托管对象——您不能将新插入的托管对象的 ID 传递给另一个上下文。
  • 在接收上下文上执行 fetch。
于 2013-02-14T14:38:40.373 回答
1

上面的单例方法非常灵巧。一个更简单的方法是将 appDelegate 视为一个单例,它就是这样。在您的 appDelegate 中创建属性,然后以下行的一个版本将检索您想要的那个。例如检索 moc

self.managedObjectContext = [(MyAppDelegate *)[[UIApplication sharedApplication] delegate] managedObjectContext];
于 2013-05-12T00:36:52.617 回答