【iOS开发每日小笔记(十一)】iOS8更新留下的“坑” NSAttributedString设置下划线 NSUnderlineStyleAttributeName 属性必须为NSNumber

这篇文章是我的【iOS开发每日小笔记】系列中的一片,记录的是今天在开发工作中遇到的,可以用很短的文章或很小的demo演示解释出来的小心得小技巧。它们可能会给用户体验、代码效率得到一些提升,或是之前自己没有接触过的技术,很开心的学到了,放在这里得瑟一下。90%的作用是帮助自己回顾、记忆、复习。

 

测试组的小伙伴们大显神威,iOS8刚发布,他们就把测试设备急速升级了,然后就是扑面而来的各种bug和他们各种幸灾乐祸的笑。没办法,老老实实修复bug!

来看看今天我遇到的一个问题:

项目中,我将一个简化的HTML格式的字符串读进内存,然后以NSHTMLTextDocumentType类型为option,初始化了一个NSAttributedString类型的实例,并将它用UITextView显示出来。

原本在iOS7中,显示没有任何问题,不论是设置颜色的地方,还是下划线,都完全OK。但是升级了iOS8以后,UITextView完全不显示了。log里的报错也是让人摸不着头脑:

2014-09-25 21:48:36.495 AttributedTextIOS8Demo[3163:24438] -[__NSCFString _getValue:forType:]: unrecognized selector sent to instance 0xae846f0
2014-09-25 21:48:36.795 AttributedTextIOS8Demo[3163:24438] <NSATSTypesetter: 0xaebd580>: Exception -[__NSCFString _getValue:forType:]: unrecognized selector sent to instance 0xae846f0 raised during typesetting layout manager <NSLayoutManager: 0xaebc9f0>
    1 containers, text backing has 69 characters
    Currently holding 69 glyphs.
    Glyph tree contents:  69 characters, 69 glyphs, 1 nodes, 32 node bytes, 512 storage bytes, 544 total bytes, 7.88 bytes per character, 7.88 bytes per glyph
    Layout tree contents:  69 characters, 69 glyphs, 0 laid glyphs, 0 laid line fragments, 1 nodes, 32 node bytes, 0 storage bytes, 32 total bytes, 0.46 bytes per character, 0.46 bytes per glyph, 0.00 laid glyphs per laid line fragment, 0.00 bytes per laid line fragment
, glyph range {0 69}. Ignoring...
2014-09-25 21:48:36.836 AttributedTextIOS8Demo[3163:24438] -[__NSCFString _getValue:forType:]: unrecognized selector sent to instance 0xae846f0
2014-09-25 21:48:36.837 AttributedTextIOS8Demo[3163:24438] <NSATSTypesetter: 0xaebd580>: Exception -[__NSCFString _getValue:forType:]: unrecognized selector sent to instance 0xae846f0 raised during typesetting layout manager <NSLayoutManager: 0xaebc9f0>
    1 containers, text backing has 69 characters
    Currently holding 69 glyphs.
    Glyph tree contents:  69 characters, 69 glyphs, 1 nodes, 32 node bytes, 512 storage bytes, 544 total bytes, 7.88 bytes per character, 7.88 bytes per glyph
    Layout tree contents:  69 characters, 69 glyphs, 0 laid glyphs, 0 laid line fragments, 1 nodes, 32 node bytes, 0 storage bytes, 32 total bytes, 0.46 bytes per character, 0.46 bytes per glyph, 0.00 laid glyphs per laid line fragment, 0.00 bytes per laid line fragment
, glyph range {0 69}. Ignoring...

我看了看,觉得大概意思就是对一个__NSCFString对象调用了一个不属于它的方法_getValue:forType:,而且,竟然没有crash!但是这也太抽象了,完全不知道问题出在哪儿。我只好使用杀手锏,逐个语句块分析,经过半个小时的各种google搜索(还得各种FQ= =)和代码分析,终于发现原来问题出在设置“下划线”这个环节上。

先来看一下我的问题代码:

 1 - (void)viewDidLoad {
 2     [super viewDidLoad];
 3     // Do any additional setup after loading the view, typically from a nib.
 4     
 5     NSString *data = [[NSBundle mainBundle] pathForResource:@"111" ofType:@"plist"];// 读取文件
 6     NSMutableDictionary *infoDict = [NSMutableDictionary dictionaryWithContentsOfFile:data];// 读取文件中的数据
 7     NSString *string = [infoDict objectForKey:@"aa"];// 取出String数据
 8     
 9     NSTextStorage *storage = [[NSTextStorage alloc] initWithData:[string dataUsingEncoding:NSUTF8StringEncoding] options:@{NSDocumentTypeDocumentAttribute:NSHTMLTextDocumentType} documentAttributes:nil error:nil];
// 以HTML的方式初始化NSTextStorage
10 [storage addAttribute:NSUnderlineStyleAttributeName value:[NSString stringWithFormat:@"%d", NSUnderlineStyleSingle] range:NSMakeRange(10, 20)];// 设置下划线 11 12 NSDictionary *dict=[NSDictionary dictionaryWithObjectsAndKeys:storage,@"storage", nil]; 13 14 UITextView *textView = [[UITextView alloc] initWithFrame:CGRectMake(0, 40, 320, 300)]; 15 textView.attributedText = [dict objectForKey:@"storage"]; 16 17 [self.view addSubview:textView]; 18 }

我的Value设置的是[NSString stringWithFormat:@"%d", NSUnderlineStyleSingle],由于iOS7中这样完全没有问题,所以我一直认为这样是对的!但是事实上,iOS8中,这样竟是错的!参考:

https://developer.apple.com/library/ios/documentation/Cocoa/Conceptual/AttributedStrings/Articles/standardAttributes.html

原来,NSUnderlineStyleAttributeName应该是NSNumber类型,改为[NSNumber numberWithInt:NSUnderlineStyleSingle]就正确无误了。

难怪出现“_getValue:forType:”这样的错误,还真的是因为内部在调用该方法的时候,发现接受消息的对象是个String类型,而不是Number。这样就说得通了!

NSUnderlineStyleAttributeName

The value of this attribute is an NSNumber object containing an integer. This value indicates whether the text is underlined and corresponds to one of the constants described in “Underline and Strikethrough Style Attributes”. The default value for this attribute is NSUnderlineStyleNone.

为什么iOS7中可以用NSString,iOS8中就会报错必须使用NSNumber呢?或许是iOS8为了适配Swift强类型,才做了这样的改变?

 

demo地址:https://github.com/pigpigdaddy/AttributedTextIOS8Demo

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。