Question

I'm trying to create thumbnails (288x288) of selected photos from iPad photo library. I have an array of ALAsset objects presented in a UITableView and as I select a row, a larger preview (288x288) of that image is displayed. In order to prevent main thread blocking, I'm trying to create the thumbnail on a background thread and also cache a copy of the thumbnail to the file system.

In a view controller when a tableview row is selected, I call loadPreviewImage in background:

- (void)tableView:(UITableView *)tableView
        didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    // get the upload object from an array that contains a ALAsset object
    upload = [uploads objectAtIndex:[indexPath row]];

    [self performSelectorInBackground:@selector(loadPreviewImage:)
                           withObject:upload];

}

I pass a custom upload object that contains asseturl property:

- (void)loadPreviewImage:(MyUploadClass*)upload
{
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 

    UIImage *preview = [upload previewImage];       
    [self performSelectorOnMainThread:@selector(setPreviewImage:)
                           withObject:preview
                        waitUntilDone:YES];

    [pool release];
}

This is called on main thread to display the thumbnail after it's loaded:

- (void)setPreviewImage:(UIImage*)image
{
    self.imageViewPreview.image = image;
    [self layoutSubviews];
}

This is a method of MyUploadClass:

- (UIImage *)previewImage
{
    __block UIImage *previewImage = [[UIImage imageWithContentsOfFile:
            [self uploadPreviewFilePath]] retain];

    if (previewImage == nil && asseturl)
    {
        ALAssetsLibrary* library = [[ALAssetsLibrary alloc] init];
        [library assetForURL:self.asseturl resultBlock:^(ALAsset *asset)
        {                         
            ALAssetRepresentation *rep = [asset defaultRepresentation]; 

            previewImage = [UIImage imageWithCGImage: [rep fullScreenImage]];
            previewImage = [[previewImage resizedImageWithContentMode:UIViewContentModeScaleAspectFit
                                             bounds:CGSizeMake(288, 288)
                               interpolationQuality:kCGInterpolationHigh] retain];

            NSData *previewData = UIImageJPEGRepresentation(previewImage, 1.0); 
            [previewData writeToFile:[self uploadPreviewFilePath] atomically:YES];   
         }
         failureBlock:^(NSError *error){ }];
         [library release];
    } 
    return [previewImage autorelease];
}

The problem is that I always get nil previewImage the first time and only after the thumbnail is cached I get an image object. What am I doing wrong? Is there a better approach to this problem?

Was it helpful?

Solution

I didn't clearly understand how the resultBlock of ALAssetsLibrary operates, my mistake was to think that the execution is linear. It turns out that in my case the resultBlock executes on the main thread while the rest of the code in previewImage executes on a background thread. I was getting nil because previewImage returned before resultBlock had a chance to end its execution. I solved the problem by replacing previewImage with the following method:

- (void) loadPreviewImage:(CGSize)size withTarget:(id)target andCallback:(SEL)callback
{
    NSString *path = [self uploadPreviewFilePath];    
    UIImage *previewImage = [UIImage imageWithContentsOfFile:path];  

    if (previewImage == nil && asseturl)
    {
        ALAssetsLibrary* library = [[ALAssetsLibrary alloc] init];
        [library assetForURL:self.asseturl resultBlock:^(ALAsset *asset)
        {
            if (asset) {                                  
              ALAssetRepresentation *rep = [asset defaultRepresentation];   

              UIImage *img = [UIImage imageWithCGImage: [rep fullScreenImage]];

              img = [img resizedImageWithContentMode:UIViewContentModeScaleAspectFit
                    bounds:size interpolationQuality:kCGInterpolationHigh];

              NSData *previewData = UIImageJPEGRepresentation(img, 1.0);                            
              [previewData writeToFile:path atomically:YES];     
              [target performSelectorOnMainThread:callback 
                                       withObject:img
                                    waitUntilDone:YES];
          }
       }
      failureBlock:^(NSError *error){ }];                        
      [library release];
  }
  else {
      [target performSelectorOnMainThread:callback withObject:img waitUntilDone:YES];
    }
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top