【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搜索(還得各種翻牆= =)和代碼分析,終於發現原來問題出在設置“下划線”這個環節上。

先來看一下我的問題代碼:

 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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM