OStack程序员社区-中国程序员成长平台

标题: ios - uitableview 更新错误 [打印本页]

作者: 菜鸟教程小白    时间: 2022-12-12 18:14
标题: ios - uitableview 更新错误

我使用以下方法更新表格 View 单元格:


- (void)imageDownloaderSDWebImageDownloader *)downloader didFinishWithIndexPathNSIndexPath *)indexPath
{
    NSArray *arr = [self.tableView indexPathsForVisibleRows];
    if ([arr containsObject:indexPath]) 
    {
        UITableViewCell *cell = [self.tableView cellForRowAtIndexPath:indexPath];//received error here
        UIImageView *imageView = (UIImageView *)[cell viewWithTag:'ICON'];
        SDWebImageManager *manager = [SDWebImageManager sharedManager];
        UIImage *image = [manager imageWithURL:downloader.url];
        imageView.image = image;
    }
}

这是 SDWebImageDownloader 的委托(delegate),更新时收到错误:

thread9:  Program received signal: "SIGABRT".

Form the device console, there is:

: *** Terminating app due to uncaught exception 'NSRangeException', reason: '*** -[__NSArrayM objectAtIndex:]: index 7 beyond bounds [0 .. 6]'
    *** First throw call stack:
    (0x335a38bf 0x300971e5 0x334ecb6b 0x30ff0eb1 0xaa0a7 0x334fd435 0xb5b13 0x30d91a91 0x30e255a1 0x36fa0c1d 0x36fa0ad8)

Then I print the arr which holds the current visible index path:

Printing description of arr:
(
    " 2 indexes [0, 1]",
    " 2 indexes [0, 2]",
    " 2 indexes [0, 3]",
    " 2 indexes [0, 4]",
    " 2 indexes [0, 5]",
    " 2 indexes [0, 6]",
    " 2 indexes [0, 7]"
)

and the received indexPath

 2 indexes [0, 7]

The indexPath is included in the visible index path, and why it still cause the NSRangeException? It looks like a bug for cellForRowAtIndexPath:indexPath, as the row of index path is 7 which is beyond the visible index path arr, am I right?

Add the eatableview delegate method:


- (UITableViewCell *)tableViewUITableView *)inTableView cellForRowAtIndexPathNSIndexPath *)indexPath
{
    static NSString *CellIdentifier = @"Cell";

    NSString *path;
    NSString *filename;

    BOOL download = YES;
    NSDictionary *tempDic = nil;
    @synchronized (documentDirectoryFileList) {
        tempDic = [self.documentDirectoryFileList objectAtIndex:indexPath.row];
        filename = [tempDic objectForKey"filename" ];

        NSURL *url = [tempDic objectForKey"url" ];
        if ( url ) {
            path = [ url path ];
            download= [ self downloadedFile:url ];

        } else {

                path = [tempDic objectForKey"filepath" ];
        }
    }

    BOOL isDirectory = FALSE;

    NSFileManager *fileManager = [[NSFileManager alloc] init];
    BOOL found = [fileManager fileExistsAtPath: path isDirectory: &isDirectory];

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    if (cell == nil) {
        cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];

        CGRect rect;
        rect = CGRectMake(5,14, 32, 32);

        cell.userInteractionEnabled = YES;

        UIImageView *imageView = [[UIImageView alloc] initWithFrame:rect];
        imageView.tag = 'ICON';
        [cell.contentView addSubview:imageView];
        [imageView release];        

        rect = CGRectMake(42, 10, 238, 22);

        UILabel *labelView = [[UILabel alloc] initWithFrame:rect];
        labelView.tag = 'NAME';
        labelView.font = [UIFont boldSystemFontOfSize:18];
        if ( download == NO )
            labelView.textColor = [UIColor lightGrayColor ];
         [cell.contentView addSubview:labelView];
        [labelView release];

        rect = CGRectMake(42, 34, 200, 20);
        labelView = [[UILabel alloc] initWithFrame:rect];
        labelView.tag = 'TIME';
        labelView.font = [UIFont systemFontOfSize:12];
        if ( download == NO )
            labelView.textColor = [UIColor lightGrayColor ];
        [cell.contentView addSubview:labelView];
        [labelView release];

        rect = CGRectMake(200, 34, 75, 20);
        labelView = [[UILabel alloc] initWithFrame:rect];
        labelView.tag = 'SIZE';
        labelView.font = [UIFont systemFontOfSize:12];
        if ( download == NO )
            labelView.textColor = [UIColor lightGrayColor ];
        labelView.textAlignment = UITextAlignmentRight;
        [cell.contentView addSubview:labelView];
        [labelView release];

    }


    // Get the time zone wrapper for the row
    UIImageView *imageView = (UIImageView *)[cell viewWithTag:'ICON'];
    imageView.image = NULL;

    NSString* extension = [[path pathExtension] lowercaseString];
    if ([extension isEqualToString: @"png"] ||
        [extension isEqualToString: @"jpg"] ||
        [extension isEqualToString: @"jpeg"] ||
        [extension isEqualToString: @"bmp"] ||
        [extension isEqualToString: @"gif"] ||
        [extension isEqualToString: @"tiff"] ||
        [extension isEqualToString: @"thm"])
    {
        NSString *realFilePath = [ fileManager destinationOfSymbolicLinkAtPath:path error:nil ];
        if ( realFilePath )
            path = realFilePath;

        NSURL *url = [[NSURL fileURLWithPath:path] URLByAppendingPathComponent"thumb.th"];
        SDWebImageManager *manager = [SDWebImageManager sharedManager];
        UIImage *temp = [manager imageWithURL:url];
        if (temp) {
            imageView.image = temp;
        }
        else
        {
            SDWebImageDownloader *downloader = [SDWebImageDownloader downloaderWithURL:url delegate:self indexPath:indexPath];
        }

    } else {

        imageView.image = [ self determineFileIcon : path ];

    }

    // Configure the cell.
    UILabel *labelView = (UILabel *)[cell viewWithTag:'NAME'];
    labelView.text = filename;
    cell.accessoryType = UITableViewCellAccessoryDetailDisclosureButton;
    if ( isDirectory ) {
        if ( isLink( path ) )
            labelView.font = [UIFont italicSystemFontOfSize:16.0];
        else
            labelView.font = [UIFont boldSystemFontOfSize:16.0];
    } else {
        if ( isLink( path ) )
            labelView.font = [UIFont italicSystemFontOfSize:16.0];
        else
            labelView.font = [UIFont systemFontOfSize:16.0];
    }

    labelView = (UILabel *)[cell viewWithTag:'TIME'];
    NSCalendar *theCalendar= [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
    NSCalendarUnit unitFlags = NSYearCalendarUnit | NSMonthCalendarUnit |  NSDayCalendarUnit | NSHourCalendarUnit | NSMinuteCalendarUnit | NSSecondCalendarUnit;

    NSDate *date = [tempDic objectForKey"date" ];
    NSDateComponents *dateComponents = [theCalendar components:unitFlags fromDate:date];

    NSInteger year = [dateComponents year];
    NSInteger month = [dateComponents month];
    NSInteger day = [dateComponents day];
    NSInteger hour = [dateComponents hour];
    NSInteger minute = [dateComponents minute];
    NSInteger second = [dateComponents second];

    [theCalendar release];
    labelView.text = [NSString stringWithFormat"%d/%02d/%02d %02d:%02d:%02d", year,month,day,hour,minute,second ];

    if ( !isDirectory ) {
        labelView = (UILabel *)[cell viewWithTag:'SIZE'];
        [labelView setHidden:NO];
        NSNumber *size = [tempDic objectForKey"filesize" ];
        float value = [ size floatValue ];
        NSString *str;
        if ( value > ( 1024*1024 ) ) {
            value = value / 1024 / 1024;
            str = [NSString stringWithFormat"%0.1f MB", value ];
        } else if ( value > 1024 ) {
            value = value / 1024;
            str = [NSString stringWithFormat"%0.1f KB", value ];
        } else {
            str = [NSString stringWithFormat"%d Bytes", [ size integerValue ] ];
        }
        labelView.text = str;
    }
    else
    {
        labelView = (UILabel *)[cell viewWithTag:'SIZE'];
        [labelView setHidden:YES];
    }

    [fileManager release];

    return cell;
}

添加于 11-17: 当“SIGABRT”收到时,documentDirectoryFileList 有对象,例如 30+。接收到的 indexPath 存在于可见索引路径数组中。但我注意到:滚动表格 View 时很容易发生。没有新对象添加到数据源。我所做的只是更新单元格上的图像。

我猜可能是: 当接收到的索引路径开始更新相应的单元格时,我碰巧滚动它并且单元格或索引路径不再可见。然后它崩溃了。



Best Answer-推荐答案


这似乎是多线程的一种问题。


- (void)imageDownloaderSDWebImageDownloader *)downloader didFinishWithIndexPathNSIndexPath *)indexPath
{


    @synchronized(tableView)
    {
        NSArray *arr = [self.tableView indexPathsForVisibleRows];
        if ([arr containsObject:indexPath]) 
        {

            UITableViewCell *cell = [self.tableView cellForRowAtIndexPath:indexPath];
            if (!cell) 
            {
                return;
            }

            UIImageView *imageView = (UIImageView *)[cell viewWithTag:'ICON'];
            SDWebImageManager *manager = [SDWebImageManager sharedManager];
            UIImage *image = [manager imageWithURL:downloader.url];
            if (image) {
                dispatch_async(dispatch_get_main_queue(), ^{
                    imageView.image = image;
                });

            }
        }

    }
}

或者你可以


- (void)imageDownloaderSDWebImageDownloader *)downloader didFinishWithIndexPathNSIndexPath *)indexPath
{


    @synchronized(tableView)
    {
        NSArray *arr = [self.tableView indexPathsForVisibleRows];
        if ([arr containsObject:indexPath]) 
        {

            dispatch_async(dispatch_get_main_queue(), ^{
                    [self.tableView reloadRowsAtIndexPaths:[NSArray arrayWithObjects:indexPath, nil] withRowAnimation:UITableViewRowAnimationNone];
                });//must be in main thread; reloadRowsAtIndexPaths: is not thread safe



        }

    }
}

关于ios - uitableview 更新错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8148811/






欢迎光临 OStack程序员社区-中国程序员成长平台 (https://ostack.cn/) Powered by Discuz! X3.4