我有一个结构用作配置文件的模型,称为ProfileModel
。这符合已创建的协议FirestoreModel
,用于将模型数据映射到Firebase的Firestore。我想把这个结构变成一个类,但我遇到了错误,我不知道如何解决。我的结构代码是这样的:
struct ProfileModel {
let id: String
let firstName: String
let surname: String
let email: String
let createdAt: Date
}
extension ProfileModel: FirestoreModel {
var documentID: String! {
return id
}
init?(modelData: FirestoreModelData) {
try? self.init(
id: modelData.documentID,
firstName: modelData.value(forKey: "firstName"),
surname: modelData.value(forKey: "surname"),
email: modelData.value(forKey: "email"),
createdAt: modelData.value(forKey: "createdAt")
)
}
}
FirestoreModel
的代码是:
private struct Property {
let label: String
let value: Any
}
struct FirestoreModelData {
let snapshot: DocumentSnapshot
var documentID: String {
return snapshot.documentID
}
var data: [String : Any]? {
return snapshot.data()
}
func value<T>(forKey key: String) throws -> T {
guard let value = data?[key] as? T else { throw ModelDataError.typeCastFailed }
return value
}
func value<T: RawRepresentable>(forKey key: String) throws -> T where T.RawValue == String {
guard let value = data?[key] as? String else { throw ModelDataError.typeCastFailed }
return T(rawValue: value)!
}
func optionalValue<T>(forKey key: String) -> T? {
return data?[key] as? T
}
enum ModelDataError: Error {
case typeCastFailed
}
}
protocol StringRawRepresentable {
var stringRawValue: String { get }
}
extension StringRawRepresentable where Self: RawRepresentable, Self.RawValue == String {
var stringRawValue: String { return rawValue }
}
protocol FirestoreModel {
init?(modelData: FirestoreModelData)
var documentID: String! { get }
var customID: String? { get }
var serialized: [String : Any?] { get }
}
extension FirestoreModel {
var serialized: [String : Any?] {
var data = [String : Any?]()
Mirror(reflecting: self).children.forEach { child in
guard let property = child.label.flatMap({ Property(label: $0, value: child.value) }) else { return }
switch property.value {
case let rawRepresentable as StringRawRepresentable:
data[property.label] = rawRepresentable.stringRawValue
default:
data[property.label] = property.value
}
}
return data
}
var customID: String? { return nil }
}
extension DocumentReference {
func setModel(_ model: FirestoreModel) {
var documentData = [String : Any]()
for (key, value) in model.serialized {
if key == "documentID" || key == model.customID { continue }
switch value {
case let rawRepresentable as StringRawRepresentable:
documentData[key] = rawRepresentable.stringRawValue
default:
documentData[key] = value
}
}
setData(documentData)
}
func getModel<Model: FirestoreModel>(_: Model.Type, completion: @escaping (Model?, Error?) -> Void) {
getDocument { snapshot, error in
if let error = error {
completion(nil, error)
return
}
guard let snapshot = snapshot else {
completion(nil, nil)
return
}
completion(Model(modelData: FirestoreModelData(snapshot: snapshot)), nil)
}
}
}
extension Query {
func getModels<Model: FirestoreModel>(_: Model.Type, completion: @escaping ([Model]?, Error?) -> Void) {
getDocuments { snapshot, error in
if let error = error {
completion(nil, error)
return
}
guard let snapshot = snapshot else {
completion(nil, nil)
return
}
completion(snapshot.documents.flatMap { Model(modelData: FirestoreModelData(snapshot: $0)) }, nil)
}
}
}
如果我将struct
更改为class
,我会遇到很多错误。这是我对class
的{{1}}代码的最新修订版:
ProfileModel
但是这对每个参数都说class ProfileModel : FirestoreModel {
let id: String
let firstName: String
let surname: String
let email: String
let createdAt: Date
required init?(modelData: FirestoreModelData) {
let id: String = modelData.documentID
guard let firstName: String = try? modelData.value(forKey: "firstName"),
let surname: String = try? modelData.value(forKey: "surname"),
let email: String = try? modelData.value(forKey: "email"),
let createdAt: Date = try? modelData.value(forKey: "createdAt")
else { return }
self.id = id
self.firstName = firstName
self.surname = surname
self.email = email
self.createdAt = createdAt
}
}
extension ProfileModel {
var documentID: String! {
return id
}
}
等。请有人帮我解决这个问题吗?谢谢!