<p> 比较长的一段时间以来,一直有一个IOS7下的crash不时的出现,近期终于找到一个crash现场,实在是个令人兴奋的消息。</p>
<p>二话不说,先上堆栈:</p>
<p>从堆栈上可以看出,crash发生在系统的API里面。而且仅仅是IOS8以下的系统才会发生,说明在IOS8以上的系统,苹果已经意识到了这个问题,将其修复了。
</p>
<p>
那么导致问题的原因究竟是什么?
</p>
<p>@"-信 仰。اللهأكبر:";
</p>
<p>如上所示,就是这个莫名其妙的字符串,导致的属性文本在计算高度的时候直接crash。利用万能的谷歌一查,这句是个阿拉伯语,大意是“真主伟大”。为何阿拉伯语会导致IOS的系统API产生crash?
</p>
<p>引用知乎上大牛们的解释:“这个 bug 应该归结为苹果从 WebCore 到 CoreText 都存在设计缺陷,对从右往左的编辑方向支持的不好,设计上没有考虑这种字符序列,而不能单纯说 WebCore 或者 CoreText 的某个地方有个小 bug。"
</p>
<p>上面这个问题算是见过的最为接近的问题了,而且crash的堆栈也及其类似。所不同的是,上面的问题发生IOS6上面(这种老古董的系统大家就别用了吧!),据说在IOS7上面已经得到修复。不过现实是目前在处理属性文本中含有阿拉伯文时,IOS系统的表现就是不稳定。
既然是这样,那一种处理方法就是将文本中的阿拉伯文过滤掉了,替换成空格或者其它什么的。以便使用不包含阿拉伯文的文本来计算size。
需要如何替换?
这里就要用到unicode编码的相关知识了。阿拉伯文一般使用unicode编码,我们找到它们的具体位置(unicode字符编码表):
阿拉伯文的范围为0x600到0x6FF。这样通过IOS的NSMutableCharacterSet对象,我们就可以找到需要过滤的字符集合。
简单的算法如下:
<code>
+ (NSCharacterSet *)tExceptSet
{
// 异常字符集合
static NSCharacterSet *exceptSet;
if (exceptSet == nil)
{
NSMutableCharacterSet *aCharacterSet = [[NSMutableCharacterSet alloc] init];
NSRange lcEnglishRange;
lcEnglishRange.location = (unsigned int)0x0600;
lcEnglishRange.length = (unsigned int)0x06ff - (unsigned int)0x0600;
[aCharacterSet addCharactersInRange:lcEnglishRange];
exceptSet = aCharacterSet;
}
return exceptSet;
}
- (NSString )ttLegalNickName:(NSString)nickName
{
NSString* legalNickName = nickName;
if(!IS_IOS_UPPER(@"8.0")) {
NSCharacterSet *illegalCharacterSet = [CommentInfo tExceptSet];
legalNickName = [[nickName componentsSeparatedByCharactersInSet:illegalCharacterSet] componentsJoinedByString:@""];
}
return legalNickName;
}
</code>
</p>
<p>
在应用上述过滤方法之后,部分IOS8以下的系统会受到小小的影响,但是相比较直接闪退而言,这样还算是比较令人接受的了。当然过滤只是一种方式,另外换一个场景,直接用上面的阿拉伯字符串算属性文本的高度,当文本很简单的时候并未发生Crash。或许这个问题还有更好的解决方案,各位如果知道,不妨告诉我。。
</p>