Alessandro
Alessandro

Reputation: 4100

Returning UIImage in block code

I am using this code to return an image:

- (UIImage *)loadThumbnailForImageForUser:(int)userID inFolder:(int)folderNumber withFileName:(NSString *)fileName ofSize:(NSString *)size{

    NSString *filePath = [NSTemporaryDirectory() stringByAppendingPathComponent:[NSString stringWithFormat:@"IMAGE%@%d", fileName, folderNumber]];

    [DropBlocks loadThumbnail:@"" ofSize:@"s" intoPath:filePath completionBlock:^(DBMetadata* metadata, NSError* error){

    }];

    UIImage *img = [UIImage imageWithContentsOfFile:filePath];
    return img;
}

The image returned is always nil. This is because the completionBlock is called later. Is there anyway to solve the issue and return the image?

Upvotes: 0

Views: 779

Answers (2)

James Webster
James Webster

Reputation: 32066

The way I usually handle this problem is to use a delegate pattern:

@protocol ImageLoadingProtocol <NSObject>

@required
-(void) imageLoaded:(UIImage*) image;

@end

In your image loader header:

__weak id<ImageLoadingProtocol> delegate;
-(void) initWithDelegate:(id<ImageLoadingProtocol>) delegate;

//or

@property (nonatomic, weak) id<ImageLoadingProtocol> delegate

In your block:

[DropBlocks loadThumbnail:@"" ofSize:@"s" intoPath:filePath completionBlock:^(DBMetadata* metadata, NSError* error){
    UIImage *img = [UIImage imageWithContentsOfFile:filePath];
    [_delegate imageLoaded:img]; 
}];

And in the class that creates your image loader:

imageLoader = [[ImageLoader alloc] initWithDelegate:self];

//or

//imageLoader.delegate = self;

Then when the block is finished your class will receive a message imageLoaded: and you should implement a method to handle it:

-(void) imageLoaded:(UIImage*) image
{
    //Here is where your image is usable.
}

Here's another solution using blocks:

- (UIImage *)loadThumbnailForImageForUser:(int)userID inFolder:(int)folderNumber withFileName:

-(NSString *)fileName ofSize:(NSString *)size completionBlock:(void( ^ )( UIImage* image )) completionBlock
{
    NSString *filePath = [NSTemporaryDirectory() stringByAppendingPathComponent:[NSString stringWithFormat:@"IMAGE%@%d", fileName, folderNumber]];

    [DropBlocks loadThumbnail:@"" ofSize:@"s" intoPath:filePath completionBlock:^(DBMetadata* metadata, NSError* error)
    {
        UIImage *img = [UIImage imageWithContentsOfFile:filePath];
        completionBlock(image);
    }];
}

Caveat: Watch out for syntax issues and memory management issues, I didn't write this in an IDE

Upvotes: 2

Wain
Wain

Reputation: 119031

No, you can't use a return and an asynchronous block. Either ensure the image is available before calling or, and this is the preferred option, add a completion block to the method and call that, supplying the image as a parameter. Then you can call the block either immediately if the image is already available or later when it is made available by the inner block.

Upvotes: 0

Related Questions