我有一个模型,它是结构的枚举。我需要使此枚举符合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来存储和检索数据。
以前当使用简单的struct
s时,我使用以下扩展进行解码;
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
的上不起作用
您需要:
- 添加
CodingKeys
枚举 - 实施
init(from:)
- 实施
encode(to:)
- 添加
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"))