Reputation: 12007
I have an iOS
project which is pulling images from a datasource method. I would like to be able to pull the image from the assets library
(and the code chunk below does this just fine).
However, I need this dataSource
method to return a UIImage
, but when I use the assets library methods to get the image, the image is returned in a result block. Simply putting return image
in the result block obviously does not work.
Does anyone have any idea how I can have the method return a UIImage
from inside the result block? I have seen several other SO questions about returning images within blocks, but they are say to call another method. I - unfortunately - can't do that because this method is a nimbus datasource method which must return a UIImage.
Any help or advice would be greatly appreciated! Code below:
- (UIImage *)photoAlbumScrollView: (NIPhotoAlbumScrollView *)photoAlbumScrollView
photoAtIndex: (NSInteger)photoIndex
photoSize: (NIPhotoScrollViewPhotoSize *)photoSize
isLoading: (BOOL *)isLoading
originalPhotoDimensions: (CGSize *)originalPhotoDimensions {
__block UIImage *image = nil;
ALAssetsLibrary* assetslibrary = [[ALAssetsLibrary alloc] init];
[assetslibrary assetForURL:[_photos objectAtIndex:photoIndex]
resultBlock:^(ALAsset *asset){
ALAssetRepresentation *rep = [asset defaultRepresentation];
CGImageRef imageRef = [rep fullScreenImage];
if (imageRef) {
image = [UIImage imageWithCGImage:imageRef];
}
}
failureBlock:^(NSError *error) {
//return nil;
}];
return image;
}
Upvotes: 3
Views: 575
Reputation: 41642
So I think I have a solution to your problem. The idea is to make use of a dispatch_group, since you can wait on a dispatch group - it gives you a way to block a thread until something happens. It may require that your datasource action NOT use the mainthread, but you are going to have to play with this. Lets assume that the object implementing photoAlbumScrollView is called 'obj'.
The code:
__block UIImage *image = nil;
ALAssetsLibrary* assetslibrary = [[ALAssetsLibrary alloc] init];
dispatch_queue_t queue = dispatch_queue_create("com.myApp.assetFetch", DISPATCH_QUEUE_SERIAL);
[assetslibrary assetForURL:[_photos objectAtIndex:photoIndex]
resultBlock:^(ALAsset *asset){
ALAssetRepresentation *rep = [asset defaultRepresentation];
CGImageRef imageRef = [rep fullScreenImage];
if (imageRef) {
image = [UIImage imageWithCGImage:imageRef];
}
dispatch_resume(queue);
}
failureBlock:^(NSError *error) {
dispatch_resume(queue);
}];
dispatch_suspend(queue);
dispatch_sync(queue, ^{ NSLog(@"UNSUSPEND!"); }); // ultimately a block with just a ';' in it
dispatch_release(queue);
return image;
I obviously did not test this but it or something close to it should work, assuming again that you can make this on a thread and not on the mainThread.
Upvotes: 0
Reputation: 1171
You should create an array for each image. When this data source method Is first called, you will not have an image for that index in the array. Kick off the asset call then return a place holder image. When the block returns, replace the place holder image with the asset image returned in the block. You may need to perform this on the main queue using GCD.
Upvotes: 2