Pregunta

I have a problem with cellForRowAtIndexPath always returning nil when called from tableView:cellForRowAtIndexPath:

The thing is I am actually calling cellForRowAtIndexPath inside a block inside tableView:cellForRowAtIndexPath: and I guess that this might be the problem.

I am populating cells with remote images that load (and cache) ad hoc. When the image returns fully loaded in the completion handler block (inside tableView:cellForRowAtIndexPath:) I need to get the cell again because it might have scrolled out of view... So I call cellForRowAtIndexPath to get the cell again - cellForRowAtIndexPath would only return a cell if it's visible. In my case I never get it to return anything but nil. Even though I am scrolling very slowly (or fast, or whatever speed I tried...) all I get is nil.

I'll try to get some code in here soon but until then any suggestion why this would occur - I guess the block thing would be a hint.

Here is the code: https://dl.dropboxusercontent.com/u/147970342/stackoverflow/appsappsappsappsapps.zip

The -tableView:cellForRowAtIndexPath: implementation:

-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    NSNumber* numberAppleid = self.appids[indexPath.row];
    UITableViewCell* cell = [tableView dequeueReusableCellWithIdentifier:@"Mycell" forIndexPath:indexPath];

    cell.textLabel.text = [NSString stringWithFormat:@"Appleid: %@", numberAppleid];

    NSString* appleidasstring = [NSString stringWithFormat:@"%@", numberAppleid];

    cell.imageView.hidden = YES; // Hide any previous until image loads
    [self getAppIconForAppleid:appleidasstring handlerImage:^(UIImage *image) {
        if (image == nil) {
            return;
        }

        DLog(@"cellForRowAtIndexPath tableView: %@, indexPath: %@", tableView, indexPath);
        UITableViewCell* localcell = [tableView cellForRowAtIndexPath:indexPath];
        if (localcell != nil) {
            localcell.imageView.image = image;
            localcell.imageView.hidden = NO;
        }
        else {
            DLog(@"Nah indexpath is not visible for: %@ because localcell is nil.", appleidasstring);
        }
    }];


    return cell;
}

Fixed version:

#define KEYAPPLEID  @"keyappleid"
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    NSNumber* numberAppleid = self.appids[indexPath.row];
    UITableViewCell* cell = [tableView dequeueReusableCellWithIdentifier:@"Mycell" forIndexPath:indexPath];

    cell.textLabel.text = [NSString stringWithFormat:@"Appleid: %@", numberAppleid];

    NSString* appleidasstring = [NSString stringWithFormat:@"%@", numberAppleid];

    [cell setAssociativeObject:appleidasstring forKey:KEYAPPLEID];

    cell.imageView.hidden = YES; // Hide any previous until image loads
    [self getAppIconForAppleid:appleidasstring handlerImage:^(UIImage *image) {
        if (image == nil) {
            return;
        }

        NSString* currentappleidofcell = [cell associativeObjectForKey:KEYAPPLEID];
        if ([currentappleidofcell isEqualToString:appleidasstring]) {
            cell.imageView.image = image;
            cell.imageView.hidden = NO;
        }
        else {
            DLog(@"Returning appleid: %@ is not matching current appleid: %@", appleidasstring, currentappleidofcell);
        }
    }];


    return cell;
}

And this category is needed: https://stackoverflow.com/a/10319083/129202

¿Fue útil?

Solución

If the block is within the tableView:cellForRowAtIndexPath: callback, you can just reference the cell directly in the block. The block will automatically keep the cell around until the block goes away. However, be careful of retain cycles. If the block is owned by the cell, you will have to use a weak reference to the cell.

So your implementation would look like this:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    NSNumber* numberAppleid = self.appids[indexPath.row];

    // Create your own UITableViewCell subclass that has an "appleidasstring" property
    MyTableViewCell* cell = [tableView dequeueReusableCellWithIdentifier:@"Mycell" forIndexPath:indexPath];

    cell.textLabel.text = [NSString stringWithFormat:@"Appleid: %@", numberAppleid];

    NSString* appleidasstring = [NSString stringWithFormat:@"%@", numberAppleid];

    cell.imageView.hidden = YES; // Hide any previous until image loads

    // Set the appleidasstring on the cell to be checked later
    cell. getAppIconForAppleid:appleidasstring = appleidasstring;

    // Modify the handler callback to also callback with the appleidasstring
    [self
        getAppIconForAppleid:appleidasstring
        handlerImage:^(UIImage *image, NSString *imageAppleIdaString)
        {
            if (image == nil) {
                return;
            }

            // Ensure the cell hasn't been repurposed for a
            // different imageAppleIdaString
            if ([cell.appleidasstring isEqualToString:imageAppleIdaString]) {
                cell.imageView.image = image;
                cell.imageView.hidden = NO;
            }
        }
    ];

    return cell;
}
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top