Error using Codable for NSAttributedString
Asked Answered
V

3

7

I'm trying to implement Codable for a class which contains a NSAttributedString, but I get errors at compile time:

try container.encode(str, forKey: .str)

error ambiguous reference to member 'encode(_:forKey:)'

and

str = try container.decode(NSMutableAttributedString.self, forKey: .str)

error: No 'decode' candidates produce the expected contextual type 'NSAttributedString'

I can get around it by using the NSData from the string, but thought this should work I would have thought

class Text : Codable {
    var str : NSAttributedString

    enum CodingKeys: String, CodingKey {
        case str
    }

    func encode(to encoder: Encoder) throws {
        var container = encoder.container(keyedBy: CodingKeys.self)
        try container.encode(str, forKey: .str). <-- error ambiguous reference to member 'encode(_:forKey:)'
    }

    required init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        str = try container.decode(NSMutableAttributedString.self, forKey: .str)  <-- error: No 'decode' candidates produce the expected contextual type 'NSAttributedString'
    }
}
Vertical answered 16/3, 2018 at 4:46 Comment(1)
NS(Mutable)AttributedString does not conform to CodableColloquial
A
6

NSAttributedString doesn’t conform to Codable, so you can’t do this directly.

If you just want to store the data you can implement a simple wrapper around your attributed string that conforms to Codable and use that in your data class. This is rather easy since you can convert the attributed string to Data using data(from:documentAttributes) when encoding. When decoding you first read the data and then initialize your attributed string using init(data:options:documentAttributes:). It supports various data formats including HTML, RTF and Microsoft Word.

Resist the temptation to add a Codable conformance to NSAttributedString in an extension. This will cause trouble when Apple adds this conformance or you add another library that does this.

If, on the other hand, you need this to communicate with a server or some other program, you need to exactly match the required data format. If you only need a plain string you probably should not use NSAttributedString at all. If it is some other format like markdown you could implement a wrapper that does the necessary transforms.

Affenpinscher answered 30/11, 2018 at 16:40 Comment(0)
G
0

Try using AttributedString instead of NSAttributedString

Goodly answered 12/4, 2024 at 7:4 Comment(0)
N
-1

If you want to decode&encode the textual content only and convert it back from/to NS(Mutual)AttributedString you can try something like that:

class Text : Codable {
var str : NSMutableAttributedString?

enum CodingKeys: String, CodingKey {
    case str
}

func encode(to encoder: Encoder) throws {
    var container = encoder.container(keyedBy: CodingKeys.self)
    try? container.encode(str?.string, forKey: .str)
}

required init(from decoder: Decoder) throws {
    let container = try decoder.container(keyedBy: CodingKeys.self)
    if let content =  try? container.decode(String.self, forKey: .str){
        str = NSMutableAttributedString(string: content)
        // ADD any attributes here if required...
    }
  }
}
Nightdress answered 30/11, 2018 at 15:51 Comment(4)
This of course would lose all the attributes, so its maybe not the best option to store an attributed string. If the attributes didn’t matter it probably wouldn't be an attributed string.Affenpinscher
The attributes might be stored somehow but if the content retrieved from an API for example, absolutely it will retrieve the string only then stored attributes added to it.Nightdress
True, forgot about that. Of course it all depends on where the data goes or comes from.Affenpinscher
NSAttributeString can be converted to Data using NSKeyedArchiver and back using NSKeyedUnarchiver. You could create an enclosing struct/class that conforms to Codable by saving raw data representing your NSAttributedString. Here is a working example : github.com/dvkch/SYKit/blob/master/SYKit/Utilities/…Unsaid

© 2022 - 2025 — McMap. All rights reserved.