rmaddy has invented an entirely new and amazing technique for this "old chestnut"annoying problem in iOS.
We have not had time to really test it out but it seems infinitely better than the "old way" explained in thisThe answer by manmal is the final perfected version. Cheers!
Here's an outline ofPurely for the historical record here is roughly how you'd go about doing it the basic solution.old days...it's a complete PITA
// somewhat depressingly, we have to (very carefully) convert it to "our" font // the only way is change- each"re-doing" sectionany BYother HANDformatting. // thus, forchange everyeach section you must care for bold/italicBY sectionsHAND. // the fixFontsInAttributedStringForUseInApp() call does all or most oftotal thatPITA. func fixFontsInAttributedStringForUseInApp() { cachedAttributedString?.beginEditing() let rangeAll = NSRange(location: 0, length: cachedAttributedString!.length) var boldRanges: [NSRange] = [] var italicRanges: [NSRange] = [] var boldANDItalicRanges: [NSRange] = [] // WTF right ?! cachedAttributedString?.enumerateAttribute( NSFontAttributeName, in: rangeAll, options: .longestEffectiveRangeNotRequired) { value, range, stop in if let font = value as? UIFont { let bb: Bool = font.fontDescriptor.symbolicTraits.contains(.traitBold) let ii: Bool = font.fontDescriptor.symbolicTraits.contains(.traitItalic) // you have to carefully handle the "both" case......... if bb && ii { boldANDItalicRanges.append(range) } if bb && !ii { boldRanges.append(range) } if ii && !bb { italicRanges.append(range) } } } cachedAttributedString!.setAttributes([NSFontAttributeName: font_f], range: rangeAll) for r in boldANDItalicRanges { cachedAttributedString!.addAttribute(NSFontAttributeName, value: font_fBOTH, range: r) } for r in boldRanges { cachedAttributedString!.addAttribute(NSFontAttributeName, value: font_fb, range: r) } for r in italicRanges { cachedAttributedString!.addAttribute(NSFontAttributeName, value: font_fi, range: r) } cachedAttributedString?.endEditing() } Even that part of the job is highly non-trivial, it takes some time to process. In practice you have to background it to avoid flicker.