将结构转化为类

时间:2018-01-26 12:44:27

标签: ios swift

我有一个结构用作配置文件的模型,称为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 } } 等。请有人帮我解决这个问题吗?谢谢!

0 个答案:

没有答案