我对设置核心数据堆栈的位置感到有些困惑。在Appdelegate中或使用UIManagedDocument的共享实例,在这里描述?:http://adevelopingstory.com/blog/2012/03/core-data-with-a-single-shared-uimanageddocument.html
现在我已经通过我的AppDelegate中的核心数据堆栈设置,并且我在视图控制器之间传递了我的MOC。但迁移到UIManagedDocument并创建共享实例会更好吗,所以我不必一直通过MOC?还因为它更新?
答案 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];