【问题标题】:cellForRowAtIndexPath always nil when called from block inside tableView:cellForRowAtIndexPath:当从 tableView:cellForRowAtIndexPath 中的块调用时,cellForRowAtIndexPath 始终为零:
【发布时间】:2014-04-01 03:13:48
【问题描述】:

当从 tableView:cellForRowAtIndexPath 调用时,cellForRowAtIndexPath 总是返回 nil:

问题是我实际上是在 tableView:cellForRowAtIndexPath: 内的 block 内调用 cellForRowAtIndexPath:,我猜这可能是问题所在。

我正在使用临时加载(和缓存)的远程图像填充单元格。当图像在完成处理程序块中完全加载时(在 tableView:cellForRowAtIndexPath:) 中,我需要再次获取单元格,因为它可能已经滚动出视图......所以我调用 cellForRowAtIndexPath 再次获取单元格 - cellForRowAtIndexPath 只会返回一个单元格,如果它是可见的。就我而言,我从来没有让它返回任何东西,但为零。即使我滚动得很慢(或很快,或者我尝试过的任何速度......)我得到的都是零。

我会尽快尝试在这里获取一些代码,但在那之前,任何关于为什么会发生这种情况的建议 - 我猜块的事情会是一个提示。

这里是代码:https://dl.dropboxusercontent.com/u/147970342/stackoverflow/appsappsappsappsapps.zip

-tableView:cellForRowAtIndexPath: 实现:

-(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;
}

固定版本:

#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;
}

并且需要这个分类:https://stackoverflow.com/a/10319083/129202

【问题讨论】:

    标签: ios objective-c uitableview objective-c-blocks


    【解决方案1】:

    如果块在tableView:cellForRowAtIndexPath: 回调中,您可以直接在块中引用单元格。该块将自动保留该单元格,直到该块消失。但是,请注意保留周期。如果块归单元所有,则必须使用对单元的弱引用。

    所以你的实现应该是这样的:

    - (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;
    }
    

    【讨论】:

    • 问题是单元格不能被重用,因为当块返回时它可能已经滚动到视野之外。这是一个常见错误,也是需要再次获取单元的原因。但我会尽快发布代码。
    • 这可以通过检查单元格来解决,以确保它仍然代表刚刚完成下载的块的相同图像。例如,通过将 URL 存储到单元格上的图像。
    • 这听起来像是我接下来应该尝试的。我贴出代码:dl.dropboxusercontent.com/u/147970342/stackoverflow/…
    • 顺便说一句,这非常相关stackoverflow.com/questions/22631635/…
    • 我刚刚尝试了您的建议,方法是将唯一值(在我的情况下,我使用应用程序的 Apple ID)存储到单元格中,然后在返回时进行检查。那我就不用cellForRowAtIndexPath了,就可以像你说的那样使用单元格的本地引用了。到目前为止,这似乎工作得很好。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-12-10
    • 1970-01-01
    • 2016-05-02
    • 2012-01-16
    • 2020-01-07
    相关资源
    最近更新 更多