UITableViewCell的字幕不会更新

今天我开始准备iOS8的应用程序。 我发现我的UITableCells的字幕不会在viewWillAppear内更新。 我把它归结为一个最小的例子:

我有一个静态单元格TableViewController与2个单元格(样式=副标题)一个字幕是空的另一个设置。

界面生成器screenschot

我更新这样的字幕:

 - (void) viewWillAppear:(BOOL)animated { [super viewWillAppear:animated]; [[self.without detailTextLabel] setText:@"foobar"]; [[self.with detailTextLabel] setText:@"barfoo"]; } 

虽然everythin在iOS7(和6和5)下工作,但iOS8不会更新第一个单元格的标题。

模拟器的屏幕截图

但是,当我触摸单元格时,它将更新并显示文本。

这是一个模拟器的问题? 一个错误? 难道我做错了什么?

作为一个临时工作,我简单地在文本标签中引入了一个空格,并以编程方式将标签文本设置为零,我将其设置为空格

 cell.detailTextLabel.text = @" "; 

相应地调整你的逻辑来处理一个单独的空白空间为零。

对于我来说,细节文本标签没有显示出来,即使我已经准备好了一个string在viewcontroller加载之前。 我的许多单元格中的一个将详细文本标签中的当前date显示为视图控制器出现时的默认值,但是这也不起作用。

我认为这与iOS 8不能更新文本标签的文本(如果它最初设置为零)有关。

因此,请注意,在界面构build器中,也会在原型单元中引入一个空白区域。 令人惊讶的是我的自定义单元格的标签文本工作正常。

看起来,Apple增加了一个优化,当值为零时从视图层次结构中移除detailTextLabel,并根据需要重新添加。 不幸的是,在我的testing中,它会在布局过程中被添加,但是只有它被resize以适应新的文本的布局过程之后,它的大小依然为零。 下一个布局通过(例如旋转),那么它将显示OK。

一种解决方法可能是在所有情况下将标签强制添加到视图层次结构中(似乎应该可以,如果为零)。 我有兴趣看看是否将以下类别放入您的应用程序可以修复这些问题。

 #import <objc/runtime.h> /* * In iOS8 GM (and beta5, unsure about earlier), detail-type UITableViewCells (the * ones which have a detailTextLabel) will remove that label from the view hierarchy if the * text value is nil. It will get re-added during the cell's layoutSubviews method, but... * this happens just too late for the label itself to get laid out, and its size remains * zero. When a subsequent layout call happens (eg a rotate, or scrolling the cells offscreen * and back) then things get fixed back up. However the initial display has completely blank * values. To fix this, we forcibly re-add it as a subview in both awakeFromNib and prepareForReuse. * Both places are necessary; one if the xib/storyboard has a nil value to begin with, and * the other if code explicitly sets it to nil during one layout cycle then sets it back). * Bug filed with Apple; Radar 18344249 . * * This worked fine in iOS7. */ @implementation UITableViewCell (IOS8DetailCellFix) + (void)load { if ([UIDevice currentDevice].systemVersion.intValue >= 8) { /* Swizzle the prepareForReuse method */ Method original = class_getInstanceMethod(self, @selector(prepareForReuse)); Method replace = class_getInstanceMethod(self, @selector(_detailfix_prepareForReuse)); method_exchangeImplementations(original, replace); /* * Insert an awakeFromNib implementation which calls super. If that fails, then * UITableViewCell already has an implementation, and we need to swizzle it instead. * In IOS8 GM UITableViewCell does not implement the method, but they could add one * in later releases so be defensive. */ Method fixawake = class_getInstanceMethod(self, @selector(_detailfix_super_awakeFromNib)); if (!class_addMethod(self, @selector(awakeFromNib), method_getImplementation(fixawake), method_getTypeEncoding(fixawake))) { original = class_getInstanceMethod(self, @selector(_detailfix_awakeFromNib)); replace = class_getInstanceMethod(self, @selector(awakeFromNib)); method_exchangeImplementations(original, replace); } } } - (void)__detailfix_addDetailAsSubviewIfNeeded { /* * UITableViewCell seems to return nil if the cell style does not have a detail. * If it returns non-nil, force add it as a contentView subview so that it gets * view layout processing at the right times. */ UILabel *detailLabel = self.detailTextLabel; if (detailLabel != nil && detailLabel.superview == nil) { [self.contentView addSubview:detailLabel]; } } - (void)_detailfix_super_awakeFromNib { [super awakeFromNib]; [self __detailfix_addDetailAsSubviewIfNeeded]; } - (void)_detailfix_awakeFromNib { [self _detailfix_awakeFromNib]; [self __detailfix_addDetailAsSubviewIfNeeded]; } - (void)_detailfix_prepareForReuse { [self _detailfix_prepareForReuse]; [self __detailfix_addDetailAsSubviewIfNeeded]; } @end 

可能还有其他的方法 – 如果你可以在正确的时间调用setNeedsLayout,它可能会强制执行一个额外的布局过程来纠正事情,但我无法find合适的时间。

编辑:下面的评论表明,重新显示的细胞可能是一个问题。 所以,更简单的解决方法可能是调用layoutSubviews并在调用Apple的实现之前执行检查。 这可以解决所有问题,因为在布局调用期间,问题发生。 所以,下面是该修复的版本 – 我会感兴趣,看看是否有效。

 #import <objc/runtime.h> @implementation UITableViewCell (IOS8DetailCellFix) + (void)load { if ([UIDevice currentDevice].systemVersion.intValue >= 8) { Method original = class_getInstanceMethod(self, @selector(layoutSubviews)); Method replace = class_getInstanceMethod(self, @selector(_detailfix_layoutSubviews)); method_exchangeImplementations(original, replace); } } - (void)_detailfix_layoutSubviews { /* * UITableViewCell seems to return nil if the cell type does not have a detail. * If it returns non-nil, force add it as a contentView subview so that it gets * view layout processing at the right times. */ UILabel *detailLabel = self.detailTextLabel; if (detailLabel != nil && detailLabel.superview == nil) { [self.contentView addSubview:detailLabel]; } [self _detailfix_layoutSubviews]; } @end 

编辑:这个bug在iOS9中出现了。 所以,条件可以改为:

 if ([UIDevice currentDevice].systemVersion.intValue == 8) 

如果应用程序只需要支持iOS9及更高版本,则可以删除swizzle fix类别。

几天过去了,我想我将不得不使用一种解决方法:

 - (void) viewDidAppear:(BOOL)animated { [super viewDidAppear:animated]; [self.without setNeedsLayout]; } 

这有一个明显的延迟,但这是我能find的唯一方法,使文本出现,并在iOS8上可读。

证实。 如果iOS8初始化为零,则不绘制detailText。 这个简单的线应该做的伎俩。

 self.detailTextLabel.attributedText = [[NSAttributedString alloc] initWithString:@" "]; 

我有同样的问题,在cellForRowAtIndexPath我返回单元格之前调用cell.layoutSubviews() 。 它解决了这个问题。

我在iOS8上看到了这个问题的两个原因。

  1. 如果您将详细信息标签中的文本设置为nil或“”(最常见的位置是prepareForReuse和/或从故事板中删除默认文本) [如上面的答案所示,此问题已解决iOS9]

  2. 如果你inheritance了一个types为subtitle的UITableViewCell,然后以编程方式注册你在storyboard中创build的单元格。 [这是一个编程错误,你不需要注册在故事板中创build的原型单元格]