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?
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 !
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With