【问题标题】:UIManagedDocument Creation in ViewDidLoadViewDidLoad 中的 UIManagedDocument 创建
【发布时间】:2013-12-06 09:46:20
【问题描述】:

经过一些研究,我仍然不确定何时/如何创建我的 UIManagedDocument。

@interface ViewController ()
@property (strong, nonatomic) UIManagedDocument *document;
@end

@implementation ViewController

- (void) viewWillAppear:(BOOL)animated
{
[super viewWillAppear:YES];

NSFileManager *fileManager = [NSFileManager defaultManager];
NSURL *documentsDirectory = [[fileManager URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] firstObject];
NSString *documentName = @"MyDocument";
NSURL *url = [documentsDirectory URLByAppendingPathComponent:documentName];

BOOL fileExists = [[NSFileManager defaultManager] fileExistsAtPath:[url path]];

if (fileExists) {
    [self.document openWithCompletionHandler:^(BOOL success) {
        NSLog(@"Exsits dont create again");
        if (success) [self documentIsReadyCreateAndObject];
        if (!success) NSLog(@"cound not open document at %@", url);
    }];
}
else {
    // create it
    [self.document saveToURL:url forSaveOperation:UIDocumentSaveForCreating completionHandler:^(BOOL success) {
        NSLog(@"Create it");
        if (success) [self documentIsReadyCreateAndObject];
        if (!success) NSLog(@"cound not create document at %@", url);
    }];
}
}

- (void) documentIsReadyCreateAndObject
{
if (self.document.documentState == UIDocumentStateNormal) {
    NSLog(@"document is ready - create obj");
    Car *demo = [NSEntityDescription insertNewObjectForEntityForName:@"Car" inManagedObjectContext:self.document.managedObjectContext];
    demo.carName = @"xxxxx";
}
else {
    NSLog(@"Not ready to go");
}
}

- (void) fetchAndPrint
{
if (self.document.documentState == UIDocumentStateNormal) {
    NSLog(@"document is ready - print objs");
    NSFetchRequest *request = [[NSFetchRequest alloc]initWithEntityName:@"Car"];
    NSArray *results = [self.document.managedObjectContext executeFetchRequest:request error:nil];

    for (Car *aLog in results) {
        NSLog(@"\nNAME: %@", aLog.carName);
    }
}
else {
    NSLog(@"Not ready to go");
}
}

@end

【问题讨论】:

    标签: core-data uimanageddocument


    【解决方案1】:

    View Controller vs. App Delegate

    创建UIManagedDocument 的最佳时间取决于具体情况,但我发现在大多数情况下,应用程序的委托是最适合它的地方。视图控制器实际上不是创建数据库的地方。大多数时候,您将在应用程序的多个位置使用该数据库,因此创建它并不是一个特定视图控制器的任务。如果您的应用程序设计发生变化,使得该视图控制器不是屏幕上的第一个控制器,您必须获取所有代码并将其放入其他视图控制器中。

    由于 Core Data 支持的模型通常需要从许多不同的视图控制器访问,我为此使用了应用程序委托。一旦你的应用程序启动,它就会创建或打开一个数据库,视图控制器几乎可以立即使用。

    这并不意味着您也必须从应用委托访问您的文档。关于这是否是好的做法存在很多争论,但我更喜欢将文档传递给任何需要的对象,这样它的模型就不会依赖于应用程序委托。

    大多数时候,传递UIManagedDocument 的唯一原因是它的NSManagedObjectContext,因此如果您不需要任何其他与文档相关的属性,则可以考虑传递它。此外,如果您只传递一个NSManagedObject,您将自动访问其上下文,这样可以减少您必须传递文档的次数。

    迁移

    我将首先回答您的最后一个问题:不,使用传统的 Core Data 堆栈或 UIManagedDocument 与迁移(轻量级或使用映射模型)无关。 UIManagedDocument 有一个 persistentStoreOptions 属性,您可以使用它来为您处理大多数迁移。即使您需要一个映射模型,您也可以创建它,将其添加到您的包中,如果您制作了正确的映射,它会为您完成这一切。

    【讨论】:

    • 谢谢。将应用程序放入应用程序委托时应用程序崩溃,因此是问题的主要原因。视图控制器 viewDidLoad 想要访问 MOC,(但我假设设置在一个块中,可能会发生延迟),因此 viewDidLoad 尝试访问尚未设置的 MOC,因此崩溃。我不知道如何解决这个问题,使用 VC 并将我的启动代码转换为 documentIsReady 是迄今为止我让它工作的唯一方法。
    • 我仍然会在创建对象后立即传递整个文档,而不仅仅是上下文。到最终发生提取时,上下文通常已准备就绪。如果文档没有打开,它可能还没有准备好,我不确定。
    • 我刚刚将所有代码移到 viewdidload 中,而核心数据甚至没有保存对象...接近放弃此托管文档并使用普通核心数据。
    • @Smick:请使用最新的代码更新您的问题
    • @Smick:你现在在 viewWillAppear: 中打开你的文档,太晚了。在应用程序委托中打开它,但将它传递给视图控制器(即使它可能尚未打开)。然后您就可以使用它了,因为当视图出现时,它已经打开了。
    【解决方案2】:

    在 AppDelegate 中创建 UIManagedDocument,但由于创建是异步的,因此您不能依赖它在视图加载时准备好。因此,您不应尝试访问 viewDidLoad 方法中的任何内容。而是在您的 viewController 上有一个名为 displayData{} 的方法,然后从 UIManagedDocument 打开完成处理程序调用它,或者最好在文件成功创建和/或打开后发布通知。最好习惯这种异步的东西,因为 iCloud 广泛使用它。查看此链接以获取有关如何实现UIManagedDocument & iCloud Integration 的更多信息。

    - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
    {
       ...
    
        if (fileExists) {
            [self.document openWithCompletionHandler:^(BOOL success) {
    
                NSLog(@"Exsits dont create again");
                if (success) {
                   [[NSNotificationCenter defaultCenter] postNotificationName:@"DatabaseReady"
                                                            object:self];
                } else {
                   NSLog(@"cound not open document at %@", url);
                }
            }];
        }
        else {
            // create it
            [self.document saveToURL:url forSaveOperation:UIDocumentSaveForCreating completionHandler:^(BOOL success) {
                NSLog(@"Create it");
                if (success) {
                   [[NSNotificationCenter defaultCenter] postNotificationName:@"DatabaseReady"
                                                            object:self];
                } else {
                   NSLog(@"cound not create document at %@", url);
                }
            }];
        }
    }
    

    在你的 viewControllers viewDidLoad 方法中添加一个观察者来接收通知

    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(displayData) name:@"DatabaseReady" object:nil];
    

    在您的 viewControllers displayData 方法中获取 moc 并检索您的数据,您应该一切顺利。

    - (void) displayData
    {
    self.document = [(AppDelegate *)[[UIApplication sharedApplication] delegate] document];
    
    self.managedObjectContext = self.document.managedObjectContext;
    
    Car *demo = [NSEntityDescription insertNewObjectForEntityForName:@"Car" inManagedObjectContext:self.managedObjectContext];
    demo.carName = @"xxxxx ";
    }
    

    如果创建失败,我通常还会发布一条(不同的)消息,以便您可以从 viewController 向用户显示一条消息。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-04-15
      • 2012-08-22
      • 2012-05-25
      • 2012-05-06
      • 2013-03-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多