How make TimeZone: Codable?

I think you only need serialize the .identifier string value and on decode, read the .identifier back and call .init(identifier:).

How to implement Codable for this?

TimeZone already conforms to Encodable and Decodable (i.e., Codable).

In general, it is not advisable to conform types that you don't own to protocols that you also don't own. If you need to do something like that, consider creating your own wrapper class and conforming that class to the protocol in question.

Sorry I didn't look before I ask. I have something just like TimeZone: only a predefined list of these things, keyed with an identifier: String:

struct MyThing {
    let identifier: String               // unique id
    let otherValues: Int
   // lots of other properties

    init(identifier: String)? {
        // something like this:
        if let result = Self.knownList.first { $0.identifier == identifier } {
            self = result
        }
        return nil
    }
    static knownList: [MyThing] = [
        .init(identifier: "xxxx", otherValues: 100, ....)
         // all possible MyThing are defined here
]
}

I want to make MyThing: Coable

Answer:

import Foundation

let encoder = JSONEncoder()
let decoder = JSONDecoder()

struct Big {
    let location: String
    let city: String
    let region: String?
    let timezone: TimeZone
    
    // anyway to not have to define? someway to use just default?
    enum CodingKeys: String, CodingKey {
      case location
    }
    
    static let knownList: [Self] = [
        Big(location: "A", city: "London", region: "UK", timezone: TimeZone(identifier: "Europe/London")!),
        Big(location: "B", city: "Another City", region: "Nowhere", timezone: TimeZone(identifier: "America/Cancun")!),
    ]
}

extension Big: Encodable {
    func encode(to encoder: Encoder) throws {
        var container = encoder.container(keyedBy: CodingKeys.self)
        try container.encode(location, forKey: .location)
    }
}


extension Big: Decodable {
    enum DecodeError: Error {
        case keyNotFound(String)
    }

    init(from decoder: Decoder) throws {
        let value = try decoder.container(keyedBy: CodingKeys.self).decode(String.self, forKey: .location)
        guard let found = Big.knownList.first(where: { $0.location == value }) else {
            throw DecodeError.keyNotFound(value)
        }
        self = found
    }
}

let a = Big.knownList[1]

let data = try encoder.encode(a)
let string = String(data: data, encoding: .utf8)!

print(string)

let reincarnated = try decoder.decode(Big.self, from: data)
print(reincarnated)

Hopefully something like this work with NSKeyedArchiver