可编码的自定义枚举类型



我有一个模型,它是结构的枚举。我需要使此枚举符合Codable

import Foundation
enum Post: Codable {
case textPost(TextPost)
case imagePost(ImagePost)
case videoPost(VideoPost)
init(from decoder: Decoder) throws {
}
func encode(to encoder: Encoder) throws {
}
}
struct TextPost: Codable {
let documentID: String
let createdAt: Int
let organization: Organization
let title: String
let description: String
let commentTotal: Int
}
struct ImagePost: Codable {
let documentID: String
let createdAt: Int
let organization: Organization
let title: String
let description: String
let commentTotal: Int
let imageURL: String
}
struct VideoPost: Codable {
let documentID: String
let createdAt: Int
let organization: Organization
let title: String
let description: String
let commentTotal: Int
let videoURL: String
}

我正在使用Firebase中的Firestore来存储和检索数据。

以前当使用简单的structs时,我使用以下扩展进行解码;

extension QueryDocumentSnapshot {
func decode() -> [String: Any] {
var data = self.data()
data["documentID"] = documentID
return data
}
}
extension JSONDecoder {
func decodeQuery<T>(_ type: T.Type, fromJSONObject object: Any) throws -> T where T: Decodable {
return try decode(T.self, from: try JSONSerialization.data(withJSONObject: object, options: []))
}
}

我这样称呼它:

func retrievePosts(success: @escaping([Post]) -> ()) {
var posts = [Post]()
reference(to: .posts).getDocuments { (snapshot, error) in
if error != nil {
print(error as Any)
return
} else {
guard let snapshotDocuments = snapshot?.documents else { return }
for snapshot in snapshotDocuments {
if let post = try? JSONDecoder().decodeQuery(Post.self, fromJSONObject: snapshot.decode()) {
posts.append(post)
}
}
}
}
}

然而,这在enum的上不起作用

您需要:

  1. 添加CodingKeys枚举
  2. 实施init(from:)
  3. 实施encode(to:)
  4. 添加Error枚举

这是代码:

enum Post: Codable {
case textPost(TextPost)
case imagePost(ImagePost)
case videoPost(VideoPost)
init(from decoder: Decoder) throws {
let values = try decoder.container(keyedBy: CodingKeys.self)
if let value = try? values.decode(TextPost.self, forKey: .textPost) {
self = .textPost(value)
return
}
if let value = try? values.decode(ImagePost.self, forKey: .imagePost) {
self = .imagePost(value)
return
}
if let value = try? values.decode(VideoPost.self, forKey: .videoPost) {
self = .videoPost(value)
return
}
throw Error.invalidData
}
func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
switch self {
case .textPost(let value):
try container.encode(value, forKey: .textPost)
case .imagePost(let value):
try container.encode(value, forKey: .imagePost)
case .videoPost(let value):
try container.encode(value, forKey: .videoPost)
}
}
private enum CodingKeys: String, CodingKey {
case textPost
case imagePost
case videoPost
}
enum Error: Swift.Error {
case invalidData
}
}

测试

我将使用您的TextPost结构的简化版本。

do {
let post = Post.imagePost(ImagePost(documentID: "123"))
let data = try JSONEncoder().encode(post)
let decodedPost = try JSONDecoder().decode(Post.self, from: data)
print(decodedPost)
} catch {
print(error)
}

结果:

imagePost(ImagePost(documentID: "123"))

最新更新