I am trying to design a helper method which will retrieve a UIManagedDocument, then open and return it, so that I may access the same UIManagedDocument from several places in my app.
I am having trouble with the asynchronous nature of this as I am not too familiar with blocks. Ideally the sequence of events would be this:
- Class X calls the helper method to retrieve the UIManagedDocument and includes a block of code to run when the opened document is returned.
- The class method retrieves the UIManagedDocument and calls openWithCompletionHandler or saveToURL as necessary, and includes a block of code to run when the opened document is returned.
- openwithCompletionHandler or saveToURL complete their task, and return with success = YES and run the code in its block
- The class method completes its task and returns with an open UIManagedDocument and runs the code in its block
Can I pass the original block through somehow?
Here's my code so far. Any thoughts hugely appreciated, thanks.
// This is a dictionary where the keys are "Vacations" and the objects are URLs to UIManagedDocuments
static NSMutableDictionary *managedDocumentDictionary = nil;
// This typedef has been defined in .h file:
// typedef void (^completion_block_t)(UIManagedDocument *vacation);
// The idea is that this class method will run the block when its UIManagedObject has opened
@implementation MyVacationsHelper
+ (void)openVacation:(NSString *)vacationName usingBlock:(completion_block_t)completionBlock
{
// Try to retrieve the relevant UIManagedDocument from managedDocumentDictionary
UIManagedDocument *doc = [managedDocumentDictionary objectForKey:vacationName];
// Get URL for this vacation -> "<Documents Directory>/<vacationName>"
NSURL *url = [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject];
url = [url URLByAppendingPathComponent:vacationName];
// If UIManagedObject was not retrieved, create it
if (!doc) {
// Create UIManagedDocument with this URL
doc = [[UIManagedDocument alloc] initWithFileURL:url];
// Add to managedDocumentDictionary
[managedDocumentDictionary setObject:doc forKey:vacationName];
}
// If document exists on disk...
if ([[NSFileManager defaultManager] fileExistsAtPath:[url path]])
{
[doc openWithCompletionHandler:^(BOOL success)
{
// Can I call the completionBlock from above in here?
// How do I pass back the opened UIDocument
}];
} else {
[doc saveToURL:url
forSaveOperation:UIDocumentSaveForCreating
completionHandler:^(BOOL success)
{
// As per comments above
}];
}
}
You can execute the block with completionBlock(doc).
[doc openWithCompletionHandler:^(BOOL success)
{
// Can I call the completionBlock from above in here?
// How do I pass back the opened UIDocument
completionBlock(doc);
}];
Let's assume that you have the following method implemented in the class that will be calling your openVacation method:
-(void)vacationOpened:(UIManagedDocument *)vacation
{
NSLog(@"My Vacation: %@", vacation.description);
}
A sample line of code that would call your openVacation method would be:
[MyVacationsHelper openVacation:@"MyVacation1" usingBlock:^(UIManagedDocument *vacation){
[self vacationOpened:vacation];
}];
The (UIManagedDocument *vacation) after the caret means that when you execute the block using the parentheses notation -- as in completionBlock(doc) --, you need to list a (UIManagedDocument *) as a parameter. The value of that parameter will be referred to as vacation inside the specified block. What I did in my block code sample above was call a method in my current class (self) and pass the parameter along to that method so that I could use it as needed (I just did an NSLog here to make sure that it worked).
I found a pretty helpful article - "Core Data with a Single Shared UIManagedDocument"
来源:https://stackoverflow.com/questions/9204025/how-do-i-create-a-global-uimanageddocument-instance-per-document-on-disk-shared