If you want to ensure that these writes happen serially, you could use a semaphore to wait for the completion of the image before initiating the next write:
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
for (UIImage *image in images) {
[library writeImageToSavedPhotosAlbum:[image CGImage] orientation:(ALAssetOrientation)[image imageOrientation] completionBlock:^(NSURL *assetURL, NSError *error) {
dispatch_semaphore_signal(semaphore); // signal when done
}];
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER); // wait for signal before continuing
}
And, since you probably don't want to block the main queue while this is going on, you might want to dispatch that whole thing to some background queue:
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
for (UIImage *image in images) {
[library writeImageToSavedPhotosAlbum:[image CGImage] orientation:(ALAssetOrientation)[image imageOrientation] completionBlock:^(NSURL *assetURL, NSError *error) {
dispatch_semaphore_signal(semaphore); // signal when done
}];
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER); // wait for signal before continuing
}
});
You could, alternatively, wrap this writeImageToSavedPhotosAlbum
in a custom NSOperation
that doesn't post isFinished
until the completion block, but that seems like overkill to me.
Having said that, I worry a little about this array of images
, where you're holding all of the UIImage
objects in memory at the same time. If they are large, or if you have many images, that could be problematic. Often you would want to simply maintain an array of, say, image names, and then instantiate the images one at a time, e.g.:
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
for (NSString *path in imagePaths) {
@autoreleasepool {
ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init];
UIImage *image = [UIImage imageWithContentsOfFile:path];
[library writeImageToSavedPhotosAlbum:[image CGImage] orientation:(ALAssetOrientation)[image imageOrientation] completionBlock:^(NSURL *assetURL, NSError *error) {
dispatch_semaphore_signal(semaphore); // signal when done
}];
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER); // wait for signal before continuing
}
}
});
One should generally be wary of any coding pattern that presumes the holding an array of large objects, like images, in memory at the same time.
If you need to frequently access these images, but don't always want to re-retrieve it from persistent storage every time, you could employ a NSCache
pattern (e.g. try to retrieve image from cache; if not found, retrieve from persistent storage and add it to the cache; upon memory pressure, empty cache), that way you enjoy the performance benefits of holding images in memory, but gracefully handle situation where the image cache consumes too much memory.