Issue

  不知道你有没有遇到过这样的问题,如下图
  
  第一个ViewController中有一个TableView,只有一个Cell,style为right detail,点击这个Cell会push进入第二个ViewController。第二个ViewController中有一个TextView,我设置了代理方法修改这个TextView的内容会更新到第一个ViewController的那个Cell的detailLabel里,但是当我清空TextView的内容后,再添加新的内容,detailLabel没法立即更新显示,当你手指(鼠标)点上去时它显示了出来,就像图片中显示的那样。
  我进行了很多次测试,发现每一次如果是TextView清空-后退-再进入-添加内容-再后退,都会导致这个问题产生,不论是真机还是模拟器。我只在iOS9和iOS8中进行了测试,发现iOS9中不存在这个问题,不知道是不是iOS8的bug,可以看看stackoverflow上这篇讨论
  我总结了三种方法来解决这个问题,demo文件传到了github上面:https://github.com/altair21/RightDetail_issueDemo,有三个branch分别是三种解决方案。
  解决问题之前需要先搞清楚问题出在哪里,我在第一个ViewController的viewWillAppear方法里在控制台输出detailLabel的frame信息,发现detailLabel的frame在每次输出时都是上一个修改之前的值,在这个问题中就是清空之后frame的宽和高还是清空之前的值,只是此时detailLabel没有文字,再添加时返回回来frame的宽和高变为(0,0),此时即使有文字也显示不出来了。
  知道问题所在之后就好解决了,我想到了三种方法,分别对应三个branch的解决方案。
  


Solution #1

  第一个思路是这样,既然布局更新不及时那就在每次第一个ViewController执行viewWillAppear时让它刷新Cell子控件的布局,具体做法就是在viewWillAppear中执行tableCell.setNeedsLayout()语句,所以这个方法看上去应该像这样:

1
2
3
4
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
tableCell.setNeedsLayout()
}

运行效果如下图

  可以看到有一些延迟,这个原因我也不知道,心里猜了个大概,但是没有查资料佐证,所以不敢乱说。


Solution #2

  第二个方法思路和第一个一样,不同的是这回我靠手动编写代码的方式来更新detailLabel的布局,你可以选择让detailLabel调用sizeToFit方法调整自己的宽度,再更新它的位置,或者选择根据传来的字符串调用sizeWithAttributes方法计算它应有的宽度,再用这个值去更新detailLabel的大小和位置,我选择的是后者
  在实现第二个ViewController的代理方法时添加了几个语句,代码看上去是这样:

1
2
3
4
5
6
7
8
9
func textViewChanged(text: String) {
rightLabel.text = text
let string = text as NSString
let contentSize = string.sizeWithAttributes([NSFontAttributeName: self.rightLabel.font])
let contentWidth = contentSize.width
let contentHeight = contentSize.height
let rightLabelMaxX = CGRectGetMaxX(rightLabel.frame)
rightLabel.frame = CGRectMake(rightLabelMaxX - contentWidth, rightLabel.frame.origin.y, contentWidth, contentHeight)
}

运行效果如下图

  可以看出显示效果和第一个方法差不多,也存在延迟


Solution #3

  前两种方法虽然显示出来了,但是存在肉眼可以观察到的延迟,非常不理想(但我还是建议你尝试一下,因为我之前测试时第二种方法是没有延迟的)。第三种方法换了一个实现思路,既然空字符串会导致detailLabel的宽和高变为(0,0),进而导致文字显示不出来,那就让它不要变为(0,0),也就是不要让它的空字符串传过来,于是将代码处理成这样:

1
2
3
4
5
6
func textViewChanged(text: String) {
if text == "" {
rightLabel.text = " "
} else {
rightLabel.text = text
}

运行效果如下图

  这一回立刻刷新了,不过有一个问题需要注意,因为我们在push进入第二个ViewController之前手动用detailLabel给它的textView的text属性赋了值,假如我们强制将空字符串转为一个空格,在push进去之后那个textView就不为空,而是有一个空格,不过解决这个问题的方法就有很多了,你可以加一个标记值,再加逻辑判断等等,或者干脆提出更好的解决方法:)