[英]iOS 7 UITextView link detection crash in UITableView
我在我的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;
}
我像这样设置单元格(特别是将UITextView.text
设置为nil
- 如本答案中所述 ):
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];
单元格是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];
但是当桌子有大约50个单元格时,当我快速滚动它时,我得到以下崩溃:
Terminating app due to uncaught exception 'NSRangeException', reason: 'NSMutableRLEArray objectAtIndex:effectiveRange:: Out of bounds'
这绝对是荒谬的 - 我注释掉这一行 - descriptionLabel.dataDetectorTypes = UIDataDetectorTypeLink;
并且应用程序停止崩溃! 我花了好几个小时试图弄清问题是什么,现在我只是得到了这个。
在iOS 7.0.3上测试
当使用相同的单元标识符时,两个具有数据类型的单元格正在出列时发生崩溃。 这似乎是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];
...
注意:将NSDataDetector *检测器初始化为静态而不是为每个单元初始化它可以提高性能。
我可以重现你的崩溃。 在TableViewCell子类中实现以下方法
- (void)prepareForReuse
{
[super prepareForReuse];
[descriptionLabel setDataDetectorTypes: UIDataDetectorTypeNone];
}
并在以下内容中添加以下调用- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
在设置文本之前:
[descriptionLabel setDataDetectorTypes: UIDataDetectorTypeLink];
为我工作。 也许它取消了在textview中持续绘制并避免崩溃的方式。
编辑:调用[descriptionLabel setDataDetectorTypes: UIDataDetectorTypeNone];
和[descriptionLabel setDataDetectorTypes: UIDataDetectorTypeLink];
在设置文本之前,似乎也解决了崩溃问题
如果您使用的是iOS6或更高版本,则可以使用NSDataDetector创建一个可归属的字符串,并将其用作TextView文本。 我们将要使用以下方法的修改版本。 该方法采用字符串和一些已预定义的属性(如字体和文本颜色),并在第100个链接后停止。 但是,它有多个电话号码的问题。 您需要为URL转发地址定义自己的代码。 NSDataDetector位取自Apple的NSDataDetector参考: https : //developer.apple.com/librarY/mac/documentation/Foundation/Reference/NSDataDetector_Class/Reference/Reference.html
NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc] initWithString:string attributes:attributes];
__block NSUInteger count = 0;
if (!_dataDetector)
{
NSError *error = nil;
_dataDetector = [NSDataDetector dataDetectorWithTypes:NSTextCheckingTypeAddress | NSTextCheckingTypePhoneNumber | NSTextCheckingTypeLink
error:&error];
}
[_dataDetector enumerateMatchesInString:string
options:0
range:NSMakeRange(0, [string length])
usingBlock:^(NSTextCheckingResult *match, NSMatchingFlags flags, BOOL *stop){
NSRange matchRange = [match range];
if ([match resultType] == NSTextCheckingTypeLink)
{
NSURL *url = [match URL];
if (url)
{
[attributedString addAttribute:NSLinkAttributeName value:url range:matchRange];
}
}
else if ([match resultType] == NSTextCheckingTypePhoneNumber)
{
NSString *phoneNumber = [NSString stringWithFormat:@"tel:%@",[match phoneNumber]];
NSURL *url = [NSURL URLWithString:phoneNumber];
if (url)
{
[attributedString addAttribute:NSLinkAttributeName value:url range:matchRange];
}
}
else if ([match resultType] == NSTextCheckingTypeAddress)
{
//Warning! You must URL escape this!
NSString *address = [string substringWithRange:matchRange];
//Warning! You must URL escape this!
NSString *urlString = [NSString stringWithFormat:@"http://maps.apple.com/?q=%@",address];
NSURL *url = [NSURL URLWithString:urlString];
if (url)
{
[attributedString addAttribute:NSLinkAttributeName value:url range:matchRange];
}
}
if (++count >= 100) *stop = YES;
}];
return attributedString;
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.