Swift Failable инициализатор из XML - PullRequest
0 голосов
/ 12 октября 2019

Позвольте мне начать с того, что у меня есть работы ...

    let a:String
    let b:Int
    let c:Double

    init?(doc:XMLDocument){
        guard let tempString = (try? doc.objects(forXQuery: "path/path/A").first as? XMLNode)?.stringValue else {return nil}
        self.a = tempString
        guard let tempString2 = (try? doc.objects(forXQuery: "path/B").first as? XMLNode)?.stringValue else {return nil}
        guard let tempInt = Int(tempString2) else {return nil}
        self.b = tempInt
        guard let tempString3 = (try? doc.objects(forXQuery: "path/path/C").first as? XMLNode)?.stringValue else {return nil}
        guard let tempDouble = Double(tempString3) else {return nil}
        self.c = tempDouble
    }
}

Я не доволен этим. Я могу упростить, выполнив нулевую проверку и повторно используя временную переменную

    init?(doc:XMLDocument){
        var tempString:String?  = (try? doc.objects(forXQuery: "path/path/A").first as? XMLNode)?.stringValue
        if tempString != nil {self.a = tempString!} else {return nil}
        tempString = (try? doc.objects(forXQuery: "path/B").first as? XMLNode)?.stringValue
        if tempString != nil && Int(tempString!) != nil {self.b = Int(tempString!)!} else {return nil}
        tempString = (try? doc.objects(forXQuery: "path/path/C").first as? XMLNode)?.stringValue
        if tempString != nil && Double(tempString!) != nil {self.c = Double(tempString!)!} else {return nil}
    }

В идеале я хочу иметь возможность назначать свойства, поскольку я проверяю их, не проходя какую-то временную переменную.

что-то вроде:

struct Foo {
    let a:String
    let b:Int
    let c:Double

    init?(doc:XMLDocument){
        do {
            if case a = try (doc.objects(forXQuery: "path/path/A").first as? XMLNode)?.stringValue { } else {return nil}
            if case b = Int(try (doc.objects(forXQuery: "path/path/B").first as? XMLNode)?.stringValue ?? "ZZZ") { } else {return nil}
            if case c = Double(try (doc.objects(forXQuery: "path/path/C").first as? XMLNode)?.stringValue ?? "ZZZ") { } else {return nil}
        } catch {
            return nil
        }
     }
}

Это ошибки с использованием self без инициализации всех сохраненных свойств.

Есть ли лучший способ сделать это?

Ответы [ 2 ]

1 голос
/ 12 октября 2019

Я бы предложил добавить несколько полезных расширений для XMLDocument и XMLNode, как показано ниже,

extension XMLDocument {

    public func xmlNode(forXQuery query: String) throws -> XMLNode? {
        return try self.objects(forXQuery: query).first as? XMLNode
    }
}

extension XMLNode {

    public var intValue: Int? {
        if let value = self.stringValue, let intValue = Int(value) {
            return intValue
        }
        return nil
    }

    public var doubleValue: Double? {
        if let value = self.stringValue, let doubleValue = Double(value) {
            return doubleValue
        }
        return nil
    }
}

Итак, теперь ваша структура будет выглядеть так:

struct Foo {
    let a: String
    let b: Int
    let c: Double

    init?(doc: XMLDocument) {
        guard let a = try? doc.xmlNode(forXQuery: "path/path/A")?.stringValue,
            let b = try? doc.xmlNode(forXQuery: "path/B")?.intValue,
            let c = try? doc.xmlNode(forXQuery: "path/path/C")?.doubleValue else { return nil }
        self.a = a
        self.b = b
        self.c = c
    }
}
0 голосов
/ 12 октября 2019

на основе ответа Камрана я получил это.


extension XMLDocument {
    func firstNode(forXQuery: String) throws -> XMLNode{
        do {
            guard let temp = try self.objects(forXQuery: forXQuery).first as? XMLNode else {throw InitError() }
            return temp
        } catch {
            throw error
        }
    }
}

extension XMLNode {
    func intValue() throws -> Int {
        guard let tempString = self.stringValue else {throw InitError()}
        guard let tempInt = Int(tempString) else {throw InitError()}
        return tempInt
    }
}
extension XMLNode {
    func stringValue() throws -> String {
        guard let tempString = self.stringValue else {throw InitError()}
        return tempString
    }
}
extension XMLNode {
    func doubleValue() throws -> Double {
        guard let tempString = self.stringValue else {throw InitError()}
        guard let tempDouble = Double(tempString) else {throw InitError()}
        return tempDouble
    }
}
extension XMLNode {
    func floatValue() throws -> Float {
        guard let tempString = self.stringValue else {throw InitError()}
        guard let tempFloat = Float(tempString) else {throw InitError()}
        return tempFloat
    }
}

, что делает мой инициализатор более привлекательным для

struct Foo {
    let a:String
    let b:Int
    let c:Double

    init?(doc:XMLDocument){
        do {
            a = try doc.firstNode(forXQuery: "path/path/a").stringValue()
            b = try doc.firstNode(forXQuery: "path/path/b").intValue()
            c = try doc.firstNode(forXQuery: "path/path/c").doubleValue()
        } catch {
            return nil
        }
     }
}

Гораздо лучше, но он все еще кажется свободным.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...