I'm writing in Swift, have an app that includes multiple user-editable textFields and textViews, all with attributedText editing features.
Once edited, information is saved to a CoreData object as well as uploaded to a server for backup. The server saves the AttributedStrings as HTML, and it is converted back to NSAttributedString when downloaded/synced.
All of this works (although I get a lot of extra attributes like paragraph style added), but for some reason, my textFields, once saved and re-loaded, don't display any italic or bold font attributes (even though it exists, is uploaded, downloaded, and converted just fine). Yet the textViews, going through the same process, display the text just fine.
Any idea why a textField would not work and a textView does for displaying attributed text?
Here's some code, I can add more if I'm missing something necessary:
Sample HTML field text:
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta http-equiv="Content-Style-Type" content="text/css">
<title></title>
<meta name="Generator" content="Cocoa HTML Writer">
<style type="text/css">
p.p1 {margin: 0.0px 0.0px 0.0px 0.0px; font: 16.0px Optima; color: #000000; -webkit-text-stroke: #000000}
span.s1 {font-family: 'Optima'; font-weight: bold; font-style: normal; font-size: 16.00pt; font-kerning: none; text-shadow: 0.0px -1.0px 0.0px rgba(255, 255, 255, 0)}
span.s2 {font-family: 'Optima-Regular'; font-weight: normal; font-style: normal; font-size: 16.00pt; font-kerning: none; text-shadow: 0.0px -1.0px 0.0px rgba(255, 255, 255, 0)}
span.s3 {font-family: 'Optima'; font-weight: normal; font-style: italic; font-size: 16.00pt; font-kerning: none; text-shadow: 0.0px -1.0px 0.0px rgba(255, 255, 255, 0)}
span.s4 {font-family: 'Optima-Regular'; font-weight: normal; font-style: normal; font-size: 16.00pt; text-decoration: underline ; font-kerning: none; text-shadow: 0.0px -1.0px 0.0px rgba(255, 255, 255, 0)}
</style>
</head>
<body>
<p class="p1"><span class="s1">Check</span><span class="s2"> </span><span class="s3">for</span><span class="s2"> </span><span class="s4">title</span><span class="s2"> here. <span class="Apple-converted-space">Â Â </span></span></p>
</body>
</html>
NSAttributeString / HTML Converters:
class AttrTextConverter {
func toHtmlString(attrString: NSAttributedString) -> String {
if let toData = attrString.dataFromRange(NSMakeRange(0, attrString.length), documentAttributes: [NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType], error: nil) {
let htmlNSString = NSString(data: toData, encoding: NSUTF8StringEncoding)
let htmlString = htmlNSString as! String
return htmlString
}
return ""
}
func toAttrString(htmlString: String) -> NSAttributedString {
let htmlNsString = htmlString as NSString
let htmlData = htmlNsString.dataUsingEncoding(NSUTF8StringEncoding)
var concreteString : NSAttributedString = NSAttributedString(string: "")
if let attrString = NSMutableAttributedString(data: htmlData!, options: [NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType, NSCharacterEncodingDocumentAttribute: NSUTF8StringEncoding], documentAttributes: nil, error: nil) {
attrString.enumerateAttribute(NSFontAttributeName, inRange: NSMakeRange(0, attrString.length), options: NSAttributedStringEnumerationOptions.allZeros) { value, range, stop in
if value != nil {
let oldFont = value as! UIFont
let oldName = oldFont.fontName
var newFont = defaultFont
if oldName.hasSuffix("-BoldOblique") || oldName.hasSuffix("-BoldItalic") {
newFont = defaultBoldItalic
} else if oldName.hasSuffix("-Bold") {
newFont = defaultBold
} else if oldName.hasSuffix("-Italic") || oldName.hasSuffix("-Oblique") {
newFont = defaultItalic
}
attrString.removeAttribute(NSFontAttributeName, range: range)
attrString.addAttribute(NSFontAttributeName, value: newFont, range: range)
} else {
attrString.addAttribute(NSFontAttributeName, value: defaultFont, range: NSMakeRange(0, attrString.length))
}
}
concreteString = attrString
}
return concreteString
}
}
And this is the display code in the viewController:
textView (WORKS):
if let mutStr = lesson?.valueForKey(record) as? NSAttributedString {
let newStr = fontSet.changeFontFamily(mutStr)
view.attributedText = newStr
}
textField (DOESN'T WORK):
if let mutStr = lesson?.valueForKey(record) as? NSAttributedString {
let newStr = fontSet.changeFontFamily(mutStr)
field.attributedText = newStr
}
Well the workaround for me was to replace the textfields with small textviews. Not a big deal, I guess, but frustrating that textFields are technically supposed to be able to handle attributed strings.