【问题标题】:Core Data initialization核心数据初始化
【发布时间】:2017-01-26 09:03:22
【问题描述】:

查看 Apple 文档,我看到他们建议从 AppDelegate 中删除 Core Data 初始化代码。他们的方法如下。

我不明白的是以下

  1. 文档中的以下句子。应用程序委托如何回调?我在下面的代码 sn-ps 中没有看到。是他们希望我们添加的内容吗?

通过使用完成块初始化一个单独的控制器对象,您已将 Core Data 堆栈移出应用程序委托,但您仍然允许对应用程序委托进行回调,以便用户界面可以知道何时开始请求数据。

  1. AppDelegate 调用 DataController 的 init,而这又调用了 initializeCoreData。但是 initializeCoreData 在后台线程中设置持久存储协调器。这意味着如果我们转换到应用程序的第一个视图并且它的视图控制器从核心数据请求数据,事情还没有建立起来。这不会是个问题吗?这是否意味着他们希望我们显示不同的启动屏幕并注册一个回调,告诉我们 CoreData 初始化在移动到实际第一个应用程序视图之前完成。

文档中的 AppDelegate 代码

-(BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {

    [self setDataController:[[DataController alloc] init];
    // Basic User Interface initialization
    return YES;
}

文档中的 DataController 代码

@interface MyDataController : NSObject

@property (strong) NSManagedObjectContext *managedObjectContext;

-(void)initializeCoreData;

@end

@implementation MyDataController

-(id)init {

    self = [super init];
    if (!self) return nil;

    [self initializeCoreData];

    return self;
}

- (void)initializeCoreData {

    NSURL *modelURL = [[NSBundle mainBundle] URLForResource:@"DataModel" withExtension:@"momd"];
    NSManagedObjectModel *mom = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
    NSAssert(mom != nil, @"Error initializing Managed Object Model");

    NSPersistentStoreCoordinator *psc = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:mom];
    NSManagedObjectContext *moc = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
    [moc setPersistentStoreCoordinator:psc];
    [self setManagedObjectContext:moc];
    NSFileManager *fileManager = [NSFileManager defaultManager];
    NSURL *documentsURL = [[fileManager URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject];
    NSURL *storeURL = [documentsURL URLByAppendingPathComponent:@"DataModel.sqlite"];

    dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void) {
        NSError *error = nil;
        NSPersistentStoreCoordinator *psc = [[self managedObjectContext] persistentStoreCoordinator];
        NSPersistentStore *store = [psc addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:&error];
        NSAssert(store != nil, @"Error initializing PSC: %@\n%@", [error localizedDescription], [error userInfo]);
    });
}

【问题讨论】:

    标签: ios objective-c core-data appdelegate apple-documentation


    【解决方案1】:

    1)

    In the Core Data programming guide you're looking at,作者正在从 App Delegate 中取出 Core Data(这往往会被许多额外的代码弄得一团糟,开发人员确实应该将它们拆分为单独的对象)。

    文档的其余部分解释:

    建议核心数据栈在自己的内部创建 顶级控制器对象和应用程序委托 初始化该控制器对象并持有对它的引用。这 行动将促进核心数据代码在其内部的整合 拥有自己的控制器并保持应用程序委托相对干净。

    还有:

    将持久存储 (NSPersistentStore) 的添加分配给 持久存储协调器 (NSPersistentStoreCoordinator) 到 后台队列。该操作可能需要未知的时间,并且 在主队列上执行它可能会阻塞用户界面 导致应用程序终止。

    一旦将持久存储添加到持久存储 协调器,然后您可以回调到主队列并请求 完成用户界面并显示给用户

    所以是的,CoreData 可能在您的第一个视图控制器显示时不一定完全启动,但是如果您有观察者从该后台队列中寻找NSNotification,您可以告诉您的 UI 何时 CoreData 准备好值得信赖。

    2)

    [DataController init]initializeCoreData 返回之前不会返回DataController 对象,因此在didFinishLaunchingWithOptions 返回之前您的UI 不会显示并且您应该已经有一个DataController 对象。

    【讨论】:

    • 我不同意。 initializeCoreData 末尾有一个 dispatch_async。因此,它将在此代码块执行之前返回。因此,当 [DataController init] 返回时,不能保证 initializeCoreDatadisaptch_async 内的块已经完成。
    • 你是对的。你需要告诉你的 UI CoreData 已经可以使用了。一种方法是通过 NSNotifications,或者另一种方法是将“属性”(例如 Bool?)设置为 true,以便在 UI 可以依赖 CoreData 时触发键值观察器。
    • @SmartHome - iCloud-core-data discussion 讨论了当临时存储被“真实”存储替换时给出的通知。我怀疑他们建议的代码可以更轻松地将具有本地商店的应用程序切换到云商店。但奇怪的是,它们没有显示如何 处理 PSCDidChange 以及如何重新显示 UI。 iCloud 文档建议您只需 reset MOC。
    【解决方案2】:

    从方法applicationDidFinishLaunchingWithOptions返回YES,是关键。

    核心数据堆栈的初始化发生在方法返回之前,或者更确切地说是在任何视图控制器被初始化之前。 一旦应用程序被通知它确实正在启动,就会初始化核心数据堆栈。只有在整个初始化过程之后,该方法才会返回YES。之后情节提要连同其初始控制器一起加载,然后加载初始控制器的viewDidLoad

    所以在某种程度上,甚至在初始控制器出现在屏幕上之前很长一段时间,Core 数据堆栈都已加载。

    希望这可以帮助您理解。

    【讨论】:

    • 我不同意。 initializeCoreData 末尾有一个 dispatch_async。因此,它将在此代码块执行之前返回。因此,当 [DataController init] 返回时,不能保证 initializeCoreDatadisaptch_async 中的块已经完成,因此不能保证当 applicationDidFinishLaunchingWithOptions 返回 YES 时该块已经执行。
    猜你喜欢
    • 1970-01-01
    • 2017-08-31
    • 1970-01-01
    • 1970-01-01
    • 2012-01-06
    • 1970-01-01
    • 1970-01-01
    • 2019-12-10
    相关资源
    最近更新 更多