I have implemented custom attributes for an AttributedString and successfully converted to NSAttributedString and used in NSTextView with custom coloring and background, works nicely!
What does not work is encoding the AttributedString to JSON. The custom attributes are not coded. I use a plain JSON encode like this:
let data = JSONEncoder().encode(object)
I assume some option is needed for the encoder to deal with the custom attributes (like when converting to NSAttributedString), but I have not been able to find any documentation on how to do this. Any suggestions?
That is correct. When using custom attributes not defined in the platform SDK, you must specify the scope containing those attributes when performing conversion or encoding/decoding operations. With conversion to NSAttributedString
, you do this with the including:
parameter (ex. NSAttributedString(myAttributedString, including: \.myCustomScope)
). To do this for encoding and decoding, you can use AttributedString
's CodableWithConfiguration
conformance. You can use the @CodableConfiguration
property wrapper in your model type like the following:
struct Message : Codable {
var recipient: Person = Person()
@CodableConfiguration(from: \.myCustomScope) var foo: AttributedString = AttributedString()
}
The property wrapper will synthesize Codable
conformance that will encode/decode your custom attributes. If you are instead writing your own encode/decode functions, you can use the functions provided on the coding containers that accept a configuration:
parameter, for example:
struct Message : Codable {
var recipient: Person = Person()
var message: AttributedString = AttributedString()
func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: MyCodingKey.self)
container.encode(recipient, forKey: .myRecipientKey)
container.encode(message, forKey: .myMessageKey, configuration: AttributeScopes.MyCustomScope.self)
}
}