utilisant ios parent de 5, enfant géré contexte de l'objet:
J'ai mes contextes d'objets gérés disposés dans cet ordre:
persistent store coordinator --->
Private Queue Managed Object Context (for saving to disk in background) ----->
Main Queue Managed Object Context (for UI) ----->
Misc. Private Managed Object Contexts (for temporary jobs like UIImagePNGRepresentation() for example)
Le modèle ressemble à:
Image Entity -> title : string , image : relationship(ImageBlob) optional
ImageBlob Entity -> image : Binary Data, imageEntity : relationship(Image)
Les relations inverses sont définies.
une fois que l'utilisateur se termine en choisissant une image:
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info
{
// get the main queue managed object context
NSManagedObjectContext* mainQueueManagedObjectContext = self.managedObjectContext;
// get the image
UIImage* image = [info objectForKey:UIImagePickerControllerOriginalImage];
// create an object, using the managed object context for the main queue
NSManagedObject *newImage = [NSEntityDescription insertNewObjectForEntityForName:@"Image" inManagedObjectContext:mainQueueManagedObjectContext];
// edit not expensive properties
[newImage setValue:[NSString stringWithFormat:@"new title %i", [self tableView:self.tableView numberOfRowsInSection:0]] forKey:@"title"];
// lets save the main context to get a permanant objectID
[self saveContextForManagedObjectContext:mainQueueManagedObjectContext];
// get the permenant objectID, Thread Safe..
NSManagedObjectID* imageObjectID = newImage.objectID;
// create a private queue concurrent managed object context
NSManagedObjectContext* privateQueueManagedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
// set the main queue as the parent
[privateQueueManagedObjectContext setParentContext:mainQueueManagedObjectContext];
// we have to use blocks here, as this managed object context will work in a private queue
[privateQueueManagedObjectContext performBlock:
^{
// get the png representation in background
NSData* data = UIImagePNGRepresentation(image);
// get the managed object using the thread safe objectID
NSManagedObject* imageObjectInPrivateQueue = [privateQueueManagedObjectContext objectWithID:imageObjectID];
// insert a new object for the ImageBlob entity
NSManagedObject *imageBlobInPrivateQueue = [NSEntityDescription insertNewObjectForEntityForName:@"ImageBlob" inManagedObjectContext:privateQueueManagedObjectContext];
// set our image data
[imageBlobInPrivateQueue setValue:data forKey:@"image"];
// set the relationship to the original record
[imageObjectInPrivateQueue setValue:imageBlobInPrivateQueue forKey:@"image"];
// save changes to private queue context to main queue context
[self saveContextForManagedObjectContext:privateQueueManagedObjectContext];
// since we are not in the main queue, we have to ask the main managed object context using performBlock
[mainQueueManagedObjectContext performBlock:
^{
// what time is it before launching save in main queue
NSDate* startDate = [NSDate date];
// launch save on main queue
[self saveContextForManagedObjectContext:mainQueueManagedObjectContext];
// what time is it after finishing save in main queue
NSDate* finishDate = [NSDate date];
// see how long UI blocked
NSLog(@"blocked UI for %f seconds", [finishDate timeIntervalSinceDate:startDate]);
}];
}];
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad)
{
[self.popOverController dismissPopoverAnimated:YES];
}
else
{
[self dismissViewControllerAnimated:YES completion:nil];
}
}
et voilà comment l'économie se fait:
-(void)saveContextForManagedObjectContext:(NSManagedObjectContext*)managedObjectContext
{
// Save the context.
NSError *error = nil;
if (![managedObjectContext save:&error]) {
// Replace this implementation with code to handle the error appropriately.
// abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
abort();
}
}
Cela réduit considérablement le blocage sur l'interface utilisateur, sur un iPhone 4, le choix d'un 5 image mégapixel va bloquer l'interface utilisateur pour seulement 0,015 secondes. D'un autre côté, le chargement de l'image bloquera également l'interface utilisateur pendant une période de temps notable. Vous pouvez donc également la charger en arrière-plan.
Au lieu d'utiliser le temporisateur, faites-le dans la méthode viewDidAppear de la vue affichée après le retrait du sélecteur. – Shizam
A partir d'iOS 5, vous pouvez utiliser le bloc d'achèvement de - (void) dismissViewControllerAnimated: (BOOL) flag completion: (void (^) (void)) achèvement; pour archiver le même. – Klaas
J'ai récemment utilisé 'dispatch_async' récemment pour cela. Je devrais probablement mettre à jour ma réponse. –