2

I have my instance variable declaration:

@interface TimelineTableViewController ()

@property (strong, nonatomic) NSMutableArray *avatars;

@end

And then my block:

void UIImageFromURL(NSURL *URL, NSString *key, void(^imageBlock)(UIImage *image), void(^errorBlock)(void)) {
    dispatch_async( dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void) {
        NSData  *data  = [[NSData alloc] initWithContentsOfURL:URL];
        UIImage *image = [[UIImage alloc] initWithData:data];
        dispatch_async( dispatch_get_main_queue(), ^(void){
            if (image != nil) {
                [self.avatars setObject:image forKey:key];
                NSLog(@"%@", self.avatars);
                imageBlock( image );
            } else {
                errorBlock();
            }
        });
    });
}

What I'm trying to do, is cache the downloaded image to an instance array to avoid re-downloading every the TableCell get's recreated. However, I get the error:

Use of undeclared identifier 'self'

I call my block like so, if that helps:

- (UITableViewCell *)tableView:(UITableView *)tableView
         cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    TweetCell *cell = (TweetCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];

    NSDictionary *tweetObject = _tweets[indexPath.row];
    NSDictionary *userObject = tweetObject[@"user"];

    NSString *avatarURL = userObject[@"profile_image_url"];
    avatarURL = [avatarURL stringByReplacingOccurrencesOfString:@"_normal"
                                                     withString:@""];
    NSURL *imageURL = [NSURL URLWithString:avatarURL];

    UIImageFromURL(imageURL, avatarURL, ^(UIImage *image) {
        [cell.avatarImage setImage:image];
    }, ^{
        NSLog(@"Failed to fetch profile picture.");
    });

    return cell;
}
benhowdle89
  • 36,900
  • 69
  • 202
  • 331

3 Answers3

2

Before your block, use this line of code to modify your self :

// Weak self
__weak MyViewController *weakSelf = self;

And call your variable like this :

void UIImageFromURL(NSURL *URL, NSString *key, void(^imageBlock)(UIImage *image), void(^errorBlock)(void)) {
    dispatch_async( dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void) {
        NSData  *data  = [[NSData alloc] initWithContentsOfURL:URL];
        UIImage *image = [[UIImage alloc] initWithData:data];
        dispatch_async( dispatch_get_main_queue(), ^(void){
            if (image != nil) {
                [weakSelf.avatars setObject:image forKey:key];
                NSLog(@"%@", weakSelf.avatars);
                imageBlock( image );
            } else {
                errorBlock();
            }
        });
    });
}

You can refer here for a powerfull answer about block!

Community
  • 1
  • 1
Jordan Montel
  • 8,227
  • 2
  • 35
  • 40
  • Hmm, I use this: `__weak TimelineTableViewController *weakSelf = self;` and still get the `use of undeclared identifier self`. I used `TimelineTableViewController` because my class is: `@interface TimelineTableViewController ()`, is this right? – benhowdle89 Apr 14 '14 at 08:18
1

Your code is not a method, but a straightforward C function. Therefore, there is no "self". Class methods start with "+", instance methods start with "-".

gnasher729
  • 51,477
  • 5
  • 75
  • 98
1

You can make UIImageFromURL() an instance method instead of a plain C function, then it has access to self:

- (void)fetchImageFromURL:(NSURL *)URL key:(NSString *)key imageBlock:(void(^)(UIImage *image))imageBlock errorBlock:(void (^)(void))errorBlock
{
    dispatch_async( dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void) {
        NSData  *data  = [[NSData alloc] initWithContentsOfURL:URL];
        UIImage *image = [[UIImage alloc] initWithData:data];
        dispatch_async( dispatch_get_main_queue(), ^(void){
            if (image != nil) {
                [self.avatars setObject:image forKey:key];
                NSLog(@"%@", self.avatars);
                imageBlock( image );
            } else {
                errorBlock();
            }
        });
    });
}

and then call it like

[self fetchImageFromURL:imageURL key:avatarURL imageBlock:^(UIImage *image) {
    [cell.avatarImage setImage:image];
} errorBlock:^{
    NSLog(@"Failed to fetch profile picture.");
}];
Martin R
  • 529,903
  • 94
  • 1,240
  • 1,382