Encoding an Object as a String in Swift

Encoding an Object as a String in Swift 图片 1

For a project I’m working on I had a need for a Codable object which could be represented as a basic text string, and specifically not a JSON string. I was eventually able to find a solution so I thought I’d document it, partially to help anyone who has the same need but also invite anyone to correct me if there is a simpler way to accomplish this.

Let’s say you have this struct:

struct MyData {
	let text: String
	let number: Int
}

And you want to encode the data as a string in the following format: My text (12)

The Encodable part of it is simple, just implement the encode method and return the formatted string in a single-value container:

extension MyData: Encodable {
	func encode(to encoder: any Encoder) throws {
		var container = encoder.singleValueContainer()
		try container.encode("\(text) (\(number))")
	}
}

Decodable is a bit more work, but also rather straightforward. I’ve chosen to implement a constructor that can initialise the struct from a source string—using regular expressions because I love problems—and then it’s just a manner of calling that initialiser from the decode initialiser, after having extracted the single-value container:

extension MyData: Decodable {
	init(from string: String) throws {
		let regex = #/^(.+?) \(([\d]+)\)$/#
		let result = try regex.wholeMatch(in: string)!

		self.text = String(result.1)  // convert to an owned String
		self.number = Int(result.2)!
	}

	init(from decoder: any Decoder) throws {
		let container = try decoder.singleValueContainer()
		let sourceString: String = try container.decode(String.self)
		try self.init(from: sourceString)
	}
}

Having this extra constructor isn’t necessary as all of it can be done in the decode constructor, but I felt it was good form. Note that this will crash if encountering a string that’s not formatted correctly, so putting in the correct safeguards is left as an exercise for the reader.

添加评论
点赞收藏
点踩分享查看原文
评论
?
参与讨论