Ramon Vasconcelos Ramon Vasconcelos - 3 months ago 183
iOS Question

NSAttributedString extension in swift 3

I'm migrating my code to swift 3 and I'm having a hard time with this extension that was working on the previous swift version.

extension Data {
var attributedString: NSAttributedString? {
do {
return try NSAttributedString(data: self, options:[NSDocumentTypeDocumentAttribute:NSHTMLTextDocumentType, NSCharacterEncodingDocumentAttribute: String.Encoding.utf8], documentAttributes: nil)
} catch let error as NSError {
print(error.localizedDescription)
}
return nil
}
}


Now when I try to call this piece of code I get an exception error like this

error: warning: couldn't get required object pointer (substituting NULL): Couldn't load 'self' because its value couldn't be evaluated


That's how I call the method from my view controller

let htmlCode = "<html><head><style type=\"text/css\">@font-face {font-family: Avenir-Roman}body {font-family: Avenir-Roman;font-size:15;margin: 0;padding: 0}</style></head><body bgcolor=\"#FBFBFB\">" + htmlBodyCode + "</body>"
newsDescription.attributedText = htmlCode.utf8Data?.attributedString

Answer

Try this:

extension Data {
    var attributedString: NSAttributedString? {
        do {
            return try NSAttributedString(data: self, options:[NSDocumentTypeDocumentAttribute:NSHTMLTextDocumentType, NSCharacterEncodingDocumentAttribute: String.Encoding.utf8.rawValue], documentAttributes: nil)
        } catch let error as NSError {
            print(error.localizedDescription)
        }
        return nil
    }
}

As described in the official reference, the value for key NSCharacterEncodingDocumentAttribute needs to be an NSNumber.

NSCharacterEncodingDocumentAttribute

The value of this attribute is an NSNumber object containing integer specifying NSStringEncoding for the file;

In older Swifts, NSStringEncoding constants are imported as UInts, so they are automatically bridged to NSNumber when converted to AnyObject, as contained in NSDictionary.

But now, Swift introduced a new enum type String.Encoding which is not originated as an Objective-C enum. And unfortunately, now any Swift types can be contained in an NSDictionary with intermediate hidden reference type _SwiftValue, which definitely is NOT an NSNumber.

So, you need to pass something which can be bridged to NSNumber as the value for key NSCharacterEncodingDocumentAttribute. In your case, rawValue would work.

In my opinion, this should be improved, and better send a bug report to Apple or swift.org.