codewithfeeling
codewithfeeling

Reputation: 6576

How can I make TextAlignment Codable in SwiftUI?

I know how to use rawValue to make custom enums adhere to the Codable protocol, but is there a way to make built-in native enums work?

I want to be able to store and retrieve TextAlignment values without having to re-invent the wheel and create some custom solution.

I can't find a single example anywhere!

Upvotes: 1

Views: 382

Answers (1)

Denis
Denis

Reputation: 3353

Unfortunately not for now.

You can possibly convert them into strings like \(alignment) and then restore by iterating through allCases and pick the one, but I do not recommend this approach as there is no guarantee that the names won't change in future.

What I would recommend - is to implement a custom Codable conformance using switch...case like:

extension TextAlignment: Codable {

    /// Adding constants to make it less error prone when refactoring
    private static var leadingIntRepresentation = -1
    private static var centerIntRepresentation = 0
    private static var trailingIntRepresentation = 1

    /// Adding a way to represent TextAlignment as Int value
    /// You may choose a different type if more appropriate
    /// for your coding practice
    private var intRepresentation: Int {
        switch self {
        case .leading: return TextAlignment.leadingIntRepresentation
        case .center: return TextAlignment.centerIntRepresentation
        case .trailing: return TextAlignment.trailingIntRepresentation
        }
    }

    /// Initializing TextAlignment using Int
    /// Making the method private as our intention is to only use it for coding
    private init(_ intRepresentation: Int) {
        switch intRepresentation {
        case TextAlignment.leadingIntRepresentation: self = .leading
        case TextAlignment.trailingIntRepresentation: self = .trailing
        default: self = .center
        }
    }

    /// Conforming to Encodable
    public func encode(to encoder: Encoder) throws {
        var container = encoder.singleValueContainer()
        try container.encode(intRepresentation)
    }

    /// Conforming to Decodable
    public init(from decoder: Decoder) throws {
        let container = try decoder.singleValueContainer()
        self.init(try container.decode(Int.self))
    }

}

This method is pretty safe. The one disadvantage is that we could possibly receive a value other than -1, 0 and 1. We would treat such a case as a center. You might consider throwing an error instead.

Upvotes: 5

Related Questions