iOS 8 Bug的Swift字体描述符符号特征替代方案

3
我正在尝试创建一个Swift自定义文本编辑器(轻量级版本),但在iOS 8上卡住了,fontDescriptorWithSymbolicTraits返回nil。是否有任何Swift的解决方法?
我创建了一个小项目样例,你可以下载并运行以下场景:
1.选择一段文本 2.点击“B”按钮 3.点击“I”按钮
应用程序会崩溃,fontDescriptorWithSymbolicTraits返回nil :(
private func addOrRemoveTraitWithName(traitName: String, traitValue: UInt32) {
    let range = self.textEditor.selectedRange
    let currentAttributesDict = self.textEditor.textStorage.attributesAtIndex(range.location, effectiveRange: nil)
    let currentFont = currentAttributesDict[NSFontAttributeName]

    let fontDescriptor = currentFont?.fontDescriptor()
    let fontNameAttribute = fontDescriptor?.fontAttributes()[UIFontDescriptorNameAttribute]

    var changedFontDescriptor: UIFontDescriptor?

    if fontNameAttribute?.rangeOfString(traitName).location == NSNotFound {
      let existingTraitsWithNewTrait = UIFontDescriptorSymbolicTraits(rawValue: fontDescriptor!.symbolicTraits.rawValue | traitValue)
      changedFontDescriptor = fontDescriptor?.fontDescriptorWithSymbolicTraits(existingTraitsWithNewTrait)
    } else {

      let existingTraitsWithoutTrait = UIFontDescriptorSymbolicTraits(rawValue: fontDescriptor!.symbolicTraits.rawValue & ~traitValue)
      changedFontDescriptor = fontDescriptor?.fontDescriptorWithSymbolicTraits(existingTraitsWithoutTrait)

    }

    let updatedFont = UIFont(descriptor: changedFontDescriptor!, size: 0.0)

    var dict = [String : AnyObject]()
    dict[NSFontAttributeName] = updatedFont
    self.textEditor.textStorage.beginEditing()
    self.textEditor.textStorage.setAttributes(dict, range: range)
    self.textEditor.textStorage.endEditing()
}

我强烈建议您快速查看示例项目

有哪些选项可供选择?

我还看到,在苹果文档上被其他人使用的方法在SDK和文档中已经缺失

其他人对此的看法:

  1. 字体描述符在iOS 8中返回nil
  2. http://www.openradar.me/19922049
1个回答

3

你说得对。很幸运,这个bug在iOS 8.3中已经被修复了。唯一可靠的解决方法是降到Core Text的级别,在那里执行功能应用。虽然有点麻烦,但能解决问题。

因此,在iOS 8.3之前,以下操作不起作用:

if let body = UIFont(name: "GillSans", size: 15),
    emphasis = body.fontDescriptor().fontDescriptorWithSymbolicTraits(.TraitItalic) {
        fbody = body
        femphasis = UIFont(descriptor: emphasis, size: 0)
}

所以你需要 import CoreText 并深入到该级别:

if let body = UIFont(name: "GillSans", size: 15),
    result = CTFontCreateCopyWithSymbolicTraits(body as CTFont, 0, nil, .ItalicTrait, .ItalicTrait) {
        fbody = body
        femphasis = result as UIFont
}

幸运的是,Swift 1.2及更高版本已经意识到 UIFont 和 CTFont 现在是toll-free bridged。在 Swift 1.2之前,这甚至更加复杂!当然,在早期系统中,它们没有toll-free bridged,这仍然更加困难。


抱歉,我不确定应该把你的代码放在哪里。 - el.severo
没有。我不会为你编写代码。我只是向您展示了使用等效的Core Text代码进行符号特征处理而不使用损坏的字体描述符。 - matt
哦,谢谢!不用在意,我并不是那个意思 :) - el.severo
你不需要“转换”。代码告诉你该做什么:你只需调用它,最终得到一个UIFont。 - matt
但是 symTraitValuesymTraitMask 不应该来自 UIFontDescription 吗? - el.severo
显示剩余3条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接