Соответствие протокола Dynami c в Swift - PullRequest
0 голосов
/ 30 апреля 2020

Привет, я изо всех сил пытаюсь решить проблему динамического соответствия протокола c на быстром языке. Пожалуйста, смотрите код.

Протокол:

protocol Object {

    init(by object: [String: Any])
}

Пользовательские структуры с соответствием объекта протокола:

struct Tree: Object {

    let treeName: String

    init(by object: [String: Any]) {

        self.treeName = object["tree"] as? String ?? "Notree"
    }
}

struct Plant: Object {

    let plantName: String

    init(by object: [String : Any]) {

        self.plantName = object["tree"] as? String ?? ""
    }
}

Приведенный выше код прекрасно работает, пока объект не станет [String: Any]. Я не могу использовать [[String: Any]], как показано ниже.

let coconut = ["tree":"Coconut"] // => This fine
let allTrees = [["tree":"Apple"],["tree":"Orange"],["tree":"Jakfruit"]] //=> Here is the problem

 let aTree = Tree(by: coconut)
 let bTree = Tree(by: ["data":allTrees])
 let cTree = Plant(by: ["data":allTrees])

Я не могу использовать массив объектов. Итак, я использовал для хранения объектов в ключе «данные». Теперь я использовал extension: Array подтверждение объекта протокола.

extension Array: Object where Element == Object{

    init(by object: [String : Any]) {

        if let data = object["data"] as? [[String: Any]]{

            self  = data.map({ (object) -> Object in

//                return Plant.init(by: object) // => Works, But I need dynamic confirmance
//                return Tree.init(by: object) // => Works, But I need dynamic confirmance

                return Object.init(by: object) //=> How can I do?
            })
        }else{

            self = []
        }
    }
}

Возвращаемое значение Object показывает ошибку Тип протокола «Объект» не может быть создан . Я много пытался решить, но не смог.

Может кто-нибудь предложить лучшую идею или решение для этой проблемы? Заранее спасибо ...

1 Ответ

1 голос
/ 30 апреля 2020

Во-первых, вы не должны использовать ограничение == Object. Вы хотите сказать, что не только [Object] является Object, но также [Plant] и [Tree] тоже Object с, верно? Для этого вы должны использовать ограничение : Object. Во-вторых, вы можете использовать Element.init для инициализации нового Element массива. Из-за ограничения Element : Object мы знаем, что инициализатор init(by:) существует:

extension Array: Object where Element: Object{

    init(by object: [String : Any]) {

        if let data = object["data"] as? [[String: Any]]{

            self  = data.map({ (object) in

                return Element.init(by: object)
            })
        }else{

            self = []
        }
    }
}

Использование:

let trees = [Tree](by: ["data": allTrees])

Вот что я думаю о более Swifty версии вашего кода, с использованием неудачных инициализаторов - инициализаторов, которые возвращают nil, когда им не удается инициализировать объект:

protocol Object {

    init?(by object: [String: Any])
}


struct Tree: Object {

    let treeName: String

    init?(by object: [String: Any]) {

        if let treeName = object["tree"] as? String {
            self.treeName = treeName
        } else {
            return nil
        }
    }
}

struct Plant: Object {

    let plantName: String

    init?(by object: [String : Any]) {

        if let plantName = object["tree"] as? String {
            self.plantName = plantName
        } else {
            return nil
        }
    }
}

extension Array: Object where Element: Object{

    init?(by object: [String : Any]) {

        if let data = object["data"] as? [[String: Any]]{
            self  = data.compactMap(Element.init)
        }else{
            return nil
        }
    }
}
...