核心数据:UIManagedDocument或AppDelegate来设置核心数据堆栈?

时间:2013-02-14 14:26:39

标签: iphone ios objective-c core-data sdk

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

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

2 个答案:

答案 0 :(得分:6)

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

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

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

以下是创建单例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

任何时候你需要上下文,你可以使用以下方式获取它:

NSManagedObjectContext *context = [DataAccessLayer context];

这种设计通常效果很好。 NSManagedObjectContext是一个非常轻量级的对象,所以没有真正的性能损失来保持它。但是,如果您需要在其他线程上执行Core Data,则设计需要稍微改变一下。来自Apple's docs

  

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

     

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

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

答案 1 :(得分:1)

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

self.managedObjectContext = [(MyAppDelegate *)[[UIApplication sharedApplication] delegate] managedObjectContext];