UITableView中的iOS 7 UITextView链接检测崩溃

Ser*_*yov 11 cocoa-touch uitableview uitextview ios

我有一个自定义UITableView单元格设置在我UITableView这样:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {

    static NSString *identifier = @"CELL_IDENTIFIER";

    SGCustomCell *cell = (SGCustomCell *)[tableView dequeueReusableCellWithIdentifier:identifier];
    if (!cell) cell = [[SGCustomCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:identifier];

    cell = [self customizedCell:cell withPost:[postsArray objectAtIndex:indexPath.row]];

    return cell;
}
Run Code Online (Sandbox Code Playgroud)

我像这样设置单元格(具体设置UITextView.textnil- 如本答案中所述):

descriptionLabel.text = nil;
descriptionLabel.text = post.postDescription;

descriptionLabel.frame = CGRectMake(leftMargin - 4, currentTitleLabel.frame.origin.y + currentTitleLabel.frame.size.height + 10, self.frame.size.width - topMargin * 3, 100);
[descriptionLabel sizeToFit];
Run Code Online (Sandbox Code Playgroud)

细胞是100%可重复使用的,UITextView就像这样(你看,没什么特别的):

descriptionLabel = [[UITextView alloc] init];
descriptionLabel.font = [UIFont fontWithName:@"HelveticaNeue" size:11];
descriptionLabel.editable = NO;
descriptionLabel.scrollEnabled = NO;
descriptionLabel.dataDetectorTypes = UIDataDetectorTypeLink;
descriptionLabel.frame = CGRectMake(leftMargin, currentTitleLabel.frame.origin.y + currentTitleLabel.frame.size.height + 10, self.frame.size.width - topMargin * 3, 10);
[self addSubview:descriptionLabel];
Run Code Online (Sandbox Code Playgroud)

但是当桌子有大约50个单元格时,当我快速滚动它,我得到以下崩溃:

Terminating app due to uncaught exception 'NSRangeException', reason: 'NSMutableRLEArray objectAtIndex:effectiveRange:: Out of bounds'
Run Code Online (Sandbox Code Playgroud)

这绝对是荒谬的 - 我评论出这一行 - descriptionLabel.dataDetectorTypes = UIDataDetectorTypeLink;应用程序停止崩溃!我花了好几个小时试图弄清问题是什么,现在我只是得到了这个.

在iOS 7.0.3上测试

Ami*_*itP 5

当使用相同的单元格标识符对两个数据类型的单元格出队时,会发生崩溃。这似乎是iOS中的错误,但Apple可能有充分的理由以这种方式实现它。(明智的记忆)

因此,唯一的100%防弹解决方案是为包含数据类型的单元格提供唯一的标识符。当然,这并不意味着您将为表中的所有单元格设置唯一的标识符,因为它会占用过多的内存,并且表的滚动速度实际上会很慢。

您可以使用NSDataDetector来确定是否在文本上找到了匹配的类型,然后才将找到的对象保存为单元格标识符,如下所示:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{

    NSString *row = [self.dataSource objectAtIndex:indexPath.row];
    static NSDataDetector *detector = nil;
    if (!detector)
    {
        NSError *error = NULL;
        detector = [[NSDataDetector alloc] initWithTypes:NSTextCheckingTypeLink | NSTextCheckingTypePhoneNumber error:&error];
    }

    NSTextCheckingResult *firstDataType = [detector firstMatchInString:row
                                                               options:0
                                                                 range:NSMakeRange(0, [row length])];
    NSString *dataTypeIdentifier = @"0";
    if (firstDataType)
    {
        if (firstDataType.resultType == NSTextCheckingTypeLink)
            dataTypeIdentifier = [(NSURL *)[firstDataType URL] absoluteString];
        else if (firstDataType.resultType == NSTextCheckingTypePhoneNumber)
            dataTypeIdentifier = [firstDataType phoneNumber];
    }

    NSString *CellIdentifier = [NSString stringWithFormat:@"Cell_%@", dataTypeIdentifier];

    UITableViewCell *cell = (UITableViewCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
...
Run Code Online (Sandbox Code Playgroud)

注意:将NSDataDetector * detector初始化为静态而不是为每个单元初始化它都可以提高性能。