iOS 7中UITableView中UITextViews的链接检测错误

46

我有一些自定义的UITableViewCells,其中包含UITextView。在Interface Builder中启用了UITextView中的链接检测。当我首次加载表视图时,一切似乎正常,但当我上下滚动表视图时,链接检测就会出现问题。具体来说,那些只包含普通文本的单元格(最初呈现为正常状态)会被显示为链接(文本视图中的所有文本均为蓝色并是活动链接),而链接指向其他某些表视图单元格中的对象。例如,一个链接可能指向一个不同的表视图单元格中的网站,或者启动一个电子邮件到不同的表视图单元格中的地址。

似乎当表视图单元格被重用时,即使更新了文本视图文本,链接也会以某种方式被保存。

这只发生在iOS 7上,而不是iOS 6。它在模拟器和我的设备上都会发生。

以下是代码:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    NSString *sectionKey = [self.orderedSectionKeys objectAtIndex:indexPath.section];
    NSDictionary *infoDictionary = [[self.tableViewData objectForKey:sectionKey] objectAtIndex:indexPath.row];

    static NSString *cellIdentifier = @"InfoDefaultTableViewCell";
    InfoDefaultTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
    if (cell == nil) {        
        NSArray *topLevelObjects = [[NSBundle mainBundle] loadNibNamed:@"InfoTableViewCells" owner:self options:nil];
        cell = [topLevelObjects objectAtIndex:0];
    }

    cell.bodyTextView.text = [infoDictionary objectForKey:@"description"];

    return cell;
}

有人知道这里正在发生什么,并且如何解决吗?


我尝试在设置文本视图文本后添加此代码,尝试重置链接:

cell.bodyTextView.dataDetectorTypes = UIDataDetectorTypeNone;
cell.bodyTextView.dataDetectorTypes = UIDataDetectorTypeAddress | UIDataDetectorTypeLink | UIDataDetectorTypePhoneNumber;

但这并没有改变我所看到的行为。


尝试打印保存在 bodyTextView 中的文本:这将有助于显示 UITableViewCell 是否缓存其呈现的内容,或者检索到的字符串是否与您预期的不同。 - cbowns
我可以在设置bodyTextView后记录其文本。它记录了我期望的内容(即我设置的文本)。 - Darren
是的,我尝试过了,但没有成功。我会将我所做的添加到我的问题中。我认为这是一个UIKit的bug,但我希望能找到一种方法来绕过它,直到它被修复。 - Darren
1
明白了。我刚在另一个相关的帖子中找到了这个答案,听起来很有帮助?https://dev59.com/TGMk5IYBdhLWcg3wyw7H#18968687 - cbowns
太好了,它起作用了!我看到过那个问题,但我没有看到那个答案。谢谢!! - Darren
显示剩余5条评论
13个回答

37

这似乎是iOS 7.0中UITextView的一个错误。有一个类似的问题,提供了一个可行的解决方法:在设置新文本字符串之前将文本视图的文本设置为nil


是的,提交一个错误报告。 - nekno
5
似乎是个bug,但将文本设置为nil并没有解决它 :( - alexdd55
@BioCho 在哪个iOS版本上? - cbowns
1
@BioCho 看起来Theragon的回答可能会有所帮助(https://dev59.com/RWIk5IYBdhLWcg3wl_TE#19589680) - cbowns
3
我在iOS 8中仍然遇到这个bug。唉。 - villapossu
毫不奇怪:我没有看到任何受此影响的人谈论提交一个带有测试用例的错误报告。 - cbowns

19

这里和提供的链接中提到的几个建议都没有帮助我解决这个错误。

我尝试设置属性文本,将文本设置为 nil,将文本设置为空字符串。

最终,在重用前强制使文本视图进出可编辑模式解决了这个问题。

- (void)prepareForReuse
{
  ...
    textView.editable = YES;
    textView.editable = NO;
  ...
}

这个有效。发现它重置了textColor而不是不正确地添加链接,所以也必须重置textColor。不幸的是,Instruments告诉我,所有这些步骤结合起来甚至比在iPod Touch iOS 7.1上使用setAttributedText:还要慢。 - TalkLittle
这对我有用,但只有在更新文本属性之前也将attributedText设置为nil时才有效。 - nacross

16

这些答案都对我没用(iOS8,Swift),唯一有效的方法是先将文本设置为nil,然后使用一个不可见的空格Unicode字符在前面添加新文本(我选择了\u200B,它是ZERO WIDTH SPACE字符,但任何字符都可以):

textView.text = nil
textView.text = "​\u{200B}\(newText)"

我也行。太棒了!您有什么解释为什么会这样工作吗? - Andrei Konstantinov
使用 Objective C 对我有效:textView.text = [@"\u200B" stringByAppendingString:message.content]; - Phamer
@melvinmt 你是怎么想出这个解决方案的,这让我很困扰?这就像是最荒谬的解决方案,但它确实有效。 - rptwsthi
无法理解为什么它解决了问题,但它运行得非常好。 - rishiAgar

6

找到了更好的解决方法。每次设置文本时需要多一个步骤,但这绝对可以解决问题。

_textView.selectable = NO; // set it to NO clears all possible data detection work so far.
_textView.selectable = YES; // set it to YES so that actual links are detected.

基本上,数据检测需要将 selectable 字段设置为 YES 才能生效。当你将其设置为 NO 时,它会被完全删除。
注意:这仅适用于 ios7。

这个可以工作,但会导致手势功能错误。 - jose920405

5

在一个非常类似的问题中,将文本设置为nil对我没有用,但是像这里建议的那样将scrollEnabled设置为NO,对我起了作用。

编辑: 此外还有一个非常特殊的情况会导致问题:当一个框以链接开头,新文本被设置为空文本(@"" - 不是nil!)时,该框会“破裂”,从此任何新文本都变成链接。我的解决方案是重写setText方法,先将[super text]设置为@"x",然后再设置实际的新文本。将其设置为nil也无法解决这个问题。


你如何设置[超级文本]? - SAHM
我已经想出来了,子类化UITextView,虽然我还没有进行彻底的测试,但它似乎对我有效。 - SAHM

3
任何上述解决方案都没能奏效,我找到了一个变通方法:在每次更新单元格文本时创建一个UITextView,而不是在可重用的单元格中重复使用它。
UITableViewCellDataSource中的代码如下:
- (void)updateDescriptionWithText:(NSString *)descriptionText
{
    UITextView *descriptionTV = [[UITextView alloc] initWithFrame:aFrame];
    [descriptionTV setScrollEnabled:NO]; 
    [descriptionTV setEditable:NO]; 
    [descriptionTV setDataDetectorTypes:UIDataDetectorTypeLink]; 
    if ([descriptionV respondsToSelector:@selector(setSelectable:)]) 
     [descriptionTV  setSelectable:YES];
    [descriptionTV setText:descriptionText];
    [self addSubview:descriptionTV];
}

UITableViewCell中:

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

   [cell updateDescriptionWithText:description];
}   

你必须管理移除descriptionTV(如果你正在重用你的表格视图单元格,而且你应该重用你的表格视图单元格)。 - rptwsthi

2
似乎在设置新文本之前将文本设置为 nil 不起作用。您可能还需要能够滚动文本视图,因此设置 scrollEnabled 可能不是一个选项。但是,当您创建并设置了一个属性字符串到单元格的文本视图时,它会起作用。我使用了集合视图,但应该与表视图相同。我在collectionView:cellForItemAtIndexPath:中编写了以下行:
//get the color and other properties from your UITextView
UIColor *textColor = cell.textView.textColor;
UIFont *messageFont = cell.textView.font;

//create your attributed string
NSAttributedString *attributedString = [[NSAttributedString alloc] initWithString:yourStringForTheTextView attributes:@{NSForegroundColorAttributeName:textColor, NSFontAttributeName:messageFont}];

//set it to your UITextView
cell.textView.attributedText = attributedString;

希望这能帮助你 :).

这是唯一可行的解决方案(除了涉及每次创建新UITextView的解决方案,出于性能原因,我不想这样做)。 - Ethan
这会导致文本出现奇怪的闪烁。 - jose920405

2
您可以通过使用NSAttributedString来解决此问题。
cell.textview.attributedText = [[NSAttributedString alloc] initWithString:message.message];

这似乎是一个合适的修复。当你启用数据检测时,它们从纯文本中获取单独的属性,因此整个文本变成了NSAttributedString。 - Michał Zygar

1
这个对我来说非常可靠:

// fix url detection bug
cell.textView.dataDetectorTypes = UIDataDetectorTypeNone;
cell.textView.dataDetectorTypes = UIDataDetectorTypeLink;

1

对于我来说,没有任何建议的解决方法起作用。因此,我决定创建一个新的UITextView,并在每次重用单元格时将其替换为旧的UITextView。这并不理想,但至少可以工作。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接