如何最好地处理核心数据+ iOS的状态恢复?

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何最好地处理核心数据+ iOS的状态恢复?相关的知识,希望对你有一定的参考价值。

我想要ios 6的状态恢复添加到我只是用左右完成的应用程序。这是一个应用程序,其中模型主要来自CoreData。

作为recommended,我使用了“接力棒”的方式来移动视图控制器之间的管理对象上下文 - 我创造我的应用程序代表商务部,它传递给第一个视图控制器,它传递给在prepareForSegue第二:,它传递给在prepareForSegue:等第三

这似乎并不符合国家恢复到Jive的非常好。我能想到的唯一要做的是检索从我的应用程序委托交通部直接viewControllerWithRestorationIdentifierPath的实现:编码器:。事实上,看来苹果开发者看WWDC会议时做了类似的事情。

这是最好的/唯一途径?是否状态恢复有效突破传递的巴吞,至少对于那些恢复视图控制器?

答案

为了熟悉状态恢复我强烈推荐WWDC 2013 session What's New in State Restoration。尽管状态恢复在iOS 6中推出,较上年同期的iOS 7带来了一些显着的变化。

Passing it forward

使用“接力棒”的方法,在某些时候,创建一个根NSManagedObjectContextNSPersistentStoreCoordinator附着。上下文被传递到一个视图控制器和随后的子视图控制器反过来通过了根上下文或儿童上下文。

例如,当用户启动根NSManagedObjectContext被创建并在到根视图控制器,它管理一个NSFetchedResultsController传递的应用程序。当用户在视图控制器选择一个项目创建一个新的细节视图控制器和NSManagedObjectContext实例中通过。

Saving and Restoring State

状态恢复的是到视图控制器使用核心数据的应用程序显著的方式改变了这一点。如果用户是详细视图控制器上,并发送该应用程序到后台系统创建了用于他们离开时重构所述可见状态的有用信息恢复存档。关于视图控制器的整个链信息被写入时,以及当应用程序重新启动这个被用于重建的状态。

当发生这种情况它不使用任何自定义的初始化,塞格斯等UIStateRestoring协议定义用于编码和解码的状态,其允许一定程度的定制方法。符合NSCoding对象可以存储在恢复存档和在IOS 7状态恢复扩展到模型对象和数据源。

状态恢复的目的是只存储需要重建应用程序的可见状态的信息。对于核心数据应用,这意味着存储定位在正确的持久存储对象所需的信息。

从表面上看,这似乎很简单。在一个视图控制器管理一个NSFetchedResultsController的情况下,这可能意味着存储谓词和排序描述符。用于显示或编辑管理对象的URI表示将被添加到状态恢复存档的单个管理对象的详细视图控制器:

- (void) encodeRestorableStateWithCoder:(NSCoder *)coder {
    NSManagedObjectID   *objectID   = [[self managedObject] objectID];

    [coder encodeObject:[objectID URIRepresentation] forKey:kManagedObjectKeyPath];
    [super encodeRestorableStateWithCoder:coder];
}

当恢复的状态下的UIStateRestoring方法-decodeRestorableStateWithCoder:被调用来从归档信息恢复的对象:

  1. 从恢复存档解码URI。
  2. 从持久存储协调获取的URI管理对象ID
  3. 从该管理对象ID被管理对象上下文获得一个管理对象实例

例如:

- (void) decodeRestorableStateWithCoder:(NSCoder *)coder {
    NSURL               *objectURI  = nil;
    NSManagedObjectID   *objectID   = nil;
    NSPersistentStoreCoordinator    *coordinator    = [[self managedObjectContext] persistentStoreCoordinator];

    objectURI = [coder decodeObjectForKey:kManagedObjectKeyPath];
    objectID = [coordinator managedObjectIDForURIRepresentation:objectURI];
    [[self managedObjectContext] performBlock:^{
        NSManagedObject *object = [self managedObjectContext] objectWithID:objectID];
        [NSOperationQueue mainQueue] addOperationWithBlock:^{
            [self setManagedObject:object];
        }];
    }]; 
}

这就是事情变得更加复杂。在应用程序生命周期的地步-decodeRestorableStateWithCoder:被称为视图控制器需要正确NSManagedObjectContext

Pass the Baton vs. State Restoration: FIGHT!

随着“接力棒”接近视图控制器被实例化作为用户交互的结果,以及被管理对象的上下文中传递,这被管理对象的上下文被连接到父上下文或持久存储协调器。

在状态恢复不会发生。如果你看的过程中发生了什么插图“接力棒”与状态恢复它们可能看起来非常相似 - 他们。表示要恢复归档的接口NSCoder实例 - 在状态恢复的数据被传承下去。

不幸的是,我们需要NSManagedObjectContext信息不能被存储为恢复归档文件的一部分。 NSManagedObjectContext不符合NSCoding,但重要的部分没有。 NSPersistentStoreCoordinator没有,所以它不会被持久化。奇怪的是,一个parentContextNSManagedObjectContext财产也不会(我强烈建议申请这个雷达)。存储特定NSPersistentStore实例的URL和重建在每个视图控制器的NSPersistentStoreCoordinator可能看起来像一个有吸引力的选择,但结果将是为每个视图控制器不同的协调 - 这可能很快会导致灾难。

因此,尽管状态恢复能够提供定位在NSManagedObjectContext实体所需的信息,它不能直接提供所需要的重新创建上下文本身。

So what next?

最终所需要的视图控制器的-decodeRestorableStateWithCoder:是有它的时候状态进行编码也做了同样出身NSManagedObjectContext的一个实例。它应该有祖先的环境和持久性存储的相同的结构。

状态恢复开始在UIApplicationDelegate,几个委托方法被调用作为恢复处理(-application:willFinishLaunchingWithOptions:-application:shouldRestoreApplicationState:-didDecodeRestorableStateWithCoder:-application:viewControllerWithRestorationIdentifierPath:coder:)的一部分。它们中的每一个是从一开始自主恢复处理并一起传递信息的机会 - 诸如附加一个NSManagedObjectContext实例作为一个相关的对象引用用于恢复NSCoder

如果应用程序委托对象负责创建该对象在整个视图控制器链可以被向下推一次启动过程完成(带或不带状态恢复)根上下文。每个视图控制器将适当NSManagedObjectContext实例传递给它的子视图控制器:

@implementation UIViewController (CoreData)

- (void) setManagedObjectContext:(NSManagedObjectContext *)context {
    [[self childViewControllers] makeObjectsPerformSelector:_cmd withObject:context];
}

@end

并且提供它自己的实现每个视图控制器将创建它自己的子上下文。这还有其他的好处 - 有一个管理对象上下文的用户的任何方法应对它改变使得它更容易异步创建上下文。创建上下文本身就是快,重量轻,但加入了持久性存储到根上下文可能是非常昂贵的,不应该被允许在主队列中运行。许多应用程序在应用程序委托方法做到这一点的主队列,并最终打开文件时由操作系统被杀害的店时间过长或需要迁移。添加另一个线程的持久存储,然后发送上下文中使用它时,它已经准备好可以帮助防止这类问题的对象。

另一种方法可以利用在视图控制器响应链。在状态恢复视图控制器可以步行响应链来寻找下一个NSManagedObjectContext环比上涨,创建一个子上下文,并使用它。使用非正式的协议来实现,这是简单的,并且在溶液中是柔性的并且可适应的结果。

非正式协议的默认实现将进一步走了响应链:

@implementation UIResponder (CoreData)

- (NSManagedObjectContext *) managedObjectContext {
    NSManagedObjectContext    *result = nil;

    if ([self nextResponder] != nil){
        if ([[self nextResponder] respondsToSelector:@selector(managedObjectContext)]){
            result = [[self nextResponder] managedObjectContext];
        }
    }
    return result;
}

@end

和在应答器链中的任何对象可以实现-managedObjectContext提供一种替代实现。这包括应用程序代理,这不会参与响应链。使用上面的非正式协议,如果一个视图或视图控制器调用-managedObjectContext默认的实现将所有的方式去申请委托返回结果,除非沿途的一些其他对象提供一个非空的结果。

您还可以使用恢复类工厂,状态恢复恢复过程中重建管理对象上下文链的选项。

这些解决方案并不适合所有的应用或情况,只有你自己才能决定什么会为你工作。

另一答案

我认为处理这将是商务部在编码的最佳方式:

- (void)encodeRestorableStateWithCoder:(NSCoder *)coder

然后解码当它通过恢复:

- (void)decodeRestorableStateWithCoder:(NSCoder *)coder

这应该保留通状态恢复的指挥棒的做法。

请记住,一个使用MOC应该实现这一点,如果你用这种方法去每一个VC。

略微膨胀,利用+ (UIViewController *)viewControllerWithRestorationIdentifierPath:(NSArray *)identifierComponents coder:(NSCoder *)coder方法来初始化你的VC,那么商务部应当通过上述方法进行解码,你应该准备就绪。

This应该有希望提供足够的信息,让你尽可能去的编码,你想恢复时恢复的任何信息进行解码。

另一答案

我没有做一吨与状态恢复,但我会沿着这些路线思考:

  • 该应用是否代表先被唤醒?是否有应用程序的委托行走视图控制器的机会?
  • 虽然等待的AppDelegate视图控制器暂停可以给它的背景?

听起来状态恢复可能是一个特例,但我想探讨做出足够聪明,等待商务部要求数据之前出现在视图控制器的选项。甚至具有在视图控制器在那里它们退一步一个地方,那里的视图控制器可以等待上下文回滚状态。

另一答案

有一个API的是,该方法在UIApplication.h隐藏起来

// Register non-View/ViewController objects for state restoration so other objects can reference them within state restoration archives.
// If the object implements encode/decode, those methods will be called during save/restore.
// Obj and identifier must not be nil, or will raise UIRestorationObjectRegistrationException.
// Objects do not need to be unregistered when they are deleted, the State Restoration system will notice and stop tracking the object.
+ (void)registerObjectForStateRestoration:(id<UIStateRestoring>)object restorationIdentifier:(NSString *)restorationIdentifier NS_AVAILABLE_IOS(7_0);

在您的AppDelegate.m地说:

[UIApplication registerObjectForStateRestoration:self.persistentContainer.viewContext restorationIdentifier:@"MyViewContext"];

对于要允许的对象被注册使NSManagedObjectContext的类别实现该协议(不需要的方法)。

@interface NSManagedObjectContext (XXX) <UIStateRestoring> 

在需要被管理对象属性(例如DetailViewController)你的视图控制器编码对象和上下文。然后,在解码使用上下文找对象。

- (void)encodeRestorableStateWithCoder:(NSCoder *)coder{
    [super encodeRestorableStateWithCoder:coder];
    NSManagedObjectID *objectID = self.detailItem.objectID;
    [coder encodeObject:objectID.URIRepresentation forKey:@"detailItem"];
    [coder encodeObject:self.detailItem.managedObjectContext forKey:@"context"];
}

- (void)decodeRestorableStateWithCoder:(NSCoder *)coder {
    [super decodeRestorableStateWithCoder:coder];
    NSManagedObjectContext *context = [coder decodeObjectForKey:@"context"];
    NSURL *objectURI = [coder decodeObjectForKey:@"detailIt

以上是关于如何最好地处理核心数据+ iOS的状态恢复?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 iOS 中最好地使用 MVC

Flink 容错机制 Checkpoint 生成与恢复流程

线程的挂起和恢复 转载

iOS:备份核心数据并使用较新的模型版本进行恢复

iOS 将整个核心数据数据库保存为 JSON 字符串,反之亦然

Flink状态管理与Checkpoint实战——模拟电商订单计算过程中宕机的场景,探索宕机恢复时如何精准继续计算订单