Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

When do UIManagedDocuments close?

I'm using this blog: http://www.adevelopingstory.com/blog/2012/03/core-data-with-a-single-shared-uimanageddocument.html to create a singleton for a UIManagedDocument singleton. Here is the relevant code in BetterDatabase

//In BetterDatabase

typedef void (^OnDocumentReady) (UIManagedDocument *document);

- (void)performWithDocument:(OnDocumentReady)onDocumentReady
{
    void (^OnDocumentDidLoad)(BOOL) = ^(BOOL success) {
        onDocumentReady(self.document);
    };

    if (![[NSFileManager defaultManager] fileExistsAtPath:[self.document.fileURL path]]) {
        [self.document saveToURL:self.document.fileURL
                forSaveOperation:UIDocumentSaveForCreating
               completionHandler:OnDocumentDidLoad];
    } else if (self.document.documentState == UIDocumentStateClosed) {
        [self.document openWithCompletionHandler:OnDocumentDidLoad];
    } else if (self.document.documentState == UIDocumentStateNormal) {
        OnDocumentDidLoad(YES);
    }
}

//In other class
[[BetterDatabase sharedDocumentHandler] performWithDocument:^(UIManagedDocument * document) {
        //Do stuff 1
        //Do stuff 2
}];

My question: When can a UIManagedDocument be closed automatically? Namely, is it possible for the document to get closed (by the OS/SDK) between lines stuff 1 and stuff 2? What if the user minimizes the iPhone app and then opens it again? Will the UIManagedDocument be closed?

Another way to phrase this is: Will a UIManagedDocument ever close while I still have a strong pointer to it?

like image 875
Nosrettap Avatar asked Oct 05 '22 10:10

Nosrettap


1 Answers

to your first question, When can a UIManagedDocument be closed automatically? there's a simple answer which is "When iOS sees fit". In other words, you don't have control when this can happen (Unless you close it yourself, but that's not the point here). But you can still respond to this situation.

In particular, in the AppDelegate file, you might want to include a line to save your document in

- (void)applicationWillResignActive:(UIApplication *)application

(not necessary if you use UIManagedDoc)

Now, your app should also monitor the UIManagedDocument states change, as explained here, line "Adding an observer of the UIDocumentStateChangedNotification notification"

To your second question, the answer is YES. Ex:If you have a long background operation, and the user shutdown his/her phone, then the document will be closed. Since you are working with a UIManagedDocument, saving is done automatically, so you should not worry of having it into an inconsistent state.

If the app goes to background state and what's between stuff1 and stuff2 is critical to your app - such as filling new data - then you should think of bracketing the most critical part into a background task.

to your third question, restoring from previous state, that's really app dependent. Apple has issued a lot of documentation, here. This has to be used in conjunction with a proper response to UIManagedDocument state change, including conflicts.

To your last question, the answer is NO under normal conditions, and YES otherwise - low memory, phone shutting down -, even if your app is in the foreground.

So, in essence, you can't control when an app is terminated (battery is drained, the OS shuts down?), but you still can respond to UIManagedDocument changes, or app lifecycle changes, in a way that allows you to preserve data integrity.

EDIT:Thanks, didn't think it fully answered your question. Just in case, the post you refer to in your original question does a very good job at laying down the important suff. in particular, I took it almost verbatim, and also added my own notifications to tell views when and how they should refresh. It is not always nice to rely on Apple's DataSource mechanisms, as it can sometimes lead to race conditions that a very hard to troubleshoot (should you update a view when it's not visible for example..).

So in the two methods

- (void)objectsDidChange:(NSNotification *)notification
{
#ifdef DEBUG
    NSLog(@"NSManagedObjects did change.");
#endif
}

- (void)contextDidSave:(NSNotification *)notification
{
#ifdef DEBUG
    NSLog(@"NSManagedContext did save.");
#endif
}

the user info field in the notification tells you what's been done in the doc, ex:

userInfo = {
    inserted = "{<the Core data fields inserted>}";
    updated = "{<code data fields updated>}";
}}

and then update the views as I see fit. For example, if you receive new data from a remote server, you can count how many new fields where inserted, and update a badge count. Or send a notification so that only one view is updated, etc..

Data consistency across views is not difficult to handle with UIManagedDoc, but how to update data without generating side effects revealed very tricky.

good luck !

like image 113
Alex Avatar answered Oct 13 '22 10:10

Alex