在 UILabel 中覆盖“文本”在 iOS 6 中不起作用

Posted

技术标签:

【中文标题】在 UILabel 中覆盖“文本”在 iOS 6 中不起作用【英文标题】:Overriding "text" in UILabel does not work in iOS 6 【发布时间】:2013-01-10 12:49:58 【问题描述】:

我的类“TypographicNumberLabel”是 UILabel 的子类。此类覆盖 UILabel 的“文本”设置器和获取器,目的是在表格中生成漂亮呈现的数字。例如,它可以为右对齐、一元加号、附加单元等添加一些额外的空白。

我的问题是这个类在 ios 5.1 之前工作得非常好,但在 iOS 6 中,它已经停止工作:它现在完全按照标准 UILabel 呈现(但是当从代码访问它的属性时,它们仍然是给出正确的结果)。 由于这个类用于大量遗留代码,我真的很想修复我的原始代码,而不是使用全新的方法重写它。所以,请集中回答解释如何在 iOS 6 中为 UILabel 覆盖“-text”和“-setText:”。

这是我的代码(简化版):

@interface TypographicNumberLabel : UILabel 

        NSString *numberText;
    

    // PROPERTIES

    // "text"            will be used to set and retrieve the number string in its original version.
    //                   integerValue, doubleValue, etc. will work as expected on the string.
    // The property "text" is declared in UILabel, but overridden here!

    // "typographicText" will be used to retrieve the string exactly as it is rendered in the view.
    //                   integerValue, doubleValue, etc. WILL NOT WORK on this string.
    @property (nonatomic, readonly) NSString* typographicText;

    @end

@implementation TypographicNumberLabel

- (void) renderTypographicText

    NSString *renderedString = nil;

    if (numberText) 
    
        // Simplified example!
        // (Actual code is much longer.)

            NSString *fillCharacter = @"\u2007"; // = "Figure space" character

        renderedString = [fillCharacter stringByAppendingString: numberText];
    

    // Save the typographic version of the string in the "text" property of the superclass (UILabel)
    // (Can be retreived by the user through the "typographicText" property.)

    super.text = renderedString;


#pragma mark - Overridden UILabel accessor methods

- (NSString *) text

    return numberText;



- (void) setText:(NSString *) newText

    if (numberText != newText)
    
        NSString *oldText = numberText;
        numberText = [newText copy];
        [oldText release];
    

    [self renderTypographicText];



#pragma mark - TypographicNumberLabel accessor methods

- (NSString *) typographicText

    return super.text;


@end

使用示例(aLabel从.xib文件加载):

@property(nonatomic, retain) IBOutlet TypographicNumberLabel *aLabel;

self.aLabel.text = @"12";
int interpretedNumber = [self.aLabel.text intValue];

这种类型的代码在 iOS 5.1 和 iOS 6 中都可以正常工作,但是在 iOS 6 中屏幕上的渲染是错误的!在那里,TypographicNumberLabel 就像 UILabel 一样工作。不会添加“图形空间”字符。

【问题讨论】:

【参考方案1】:

问题出在

- (NSString *) text

    return numberText;

可以看到内部调用了方法([self text]),所以最好返回要显示的文本,否则很容易破坏内部控制逻辑:

- (NSString *) text

    return [super text];

【讨论】:

非常感谢!我错误地认为 super.text 是从内部控制逻辑调用的,因此我对 text 的重新定义无关紧要,但现在我意识到这是错误的!我也明白我将来应该避免这种黑客行为。我给你一个赞成票!然而,即使这个答案解释了我的错误,它并没有完全解决我的问题,因为它破坏了与我的遗留代码的兼容性。我的代码依赖于 text 返回未格式化的字符串,而不是印刷字符串。【参考方案2】:

提交问题后,我自己找到了解决方案。也许不是明确的解决方案,但至少是一个有用的解决方法。显然,在 iOS 6 中引入 attributedText 时,UILabel 的渲染逻辑发生了变化。我发现设置 attributedText 属性而不是 super.text会工作的。

更具体地说: renderTypographicText

中的以下行
    super.text = renderedString;

应该替换为

    if (renderedString && [UILabel instancesRespondToSelector: @selector(setAttributedText:)])
    super.attributedText = [[[NSAttributedString alloc] initWithString: renderedString] autorelease];
else
    super.text = renderedString;

然后渲染又可以正常工作了!

我承认,这有点“骇人听闻”,但它使我免于重写大量遗留代码。

【讨论】:

有趣的解决方案,我仍然计划重构:label.attributedText 将返回与label.text 相对的印刷文本 好的。只是为了澄清一下:我的“TypographicNumberLabel”除了 NSAttributedString 还做了一些其他的事情,例如大量插入数千个分隔符并附加单位,因此它们不可互换。但我同意我可能应该在未来的设计中寻求另一种解决方案。

以上是关于在 UILabel 中覆盖“文本”在 iOS 6 中不起作用的主要内容,如果未能解决你的问题,请参考以下文章

根据文本动态获取UILabel的高度为iOS 7.0和iOS 6.1返回不同的值

将文本放在 UIlabel 的顶部

Objective C - CAGradientLayer 覆盖 UILabel 中的文本?

如何使用自动布局在 iOS 中根据文本长度更改 UILabel 宽度

如何在视频上绘制文本以在 iOS 上显示字幕?

在 UILabel 中显示 HTML 文本,性能问题。 [iPhone SDK、iOS 8、Swift]