【问题标题】:Swift Failable initializer from XML来自 XML 的 Swift Failable 初始化程序
【发布时间】:2020-02-09 10:07:45
【问题描述】:

让我先说一下我的作品......

    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 会出错。

有没有更好的方法?

【问题讨论】:

    标签: swift initializer failable


    【解决方案1】:

    我建议为XMLDocumentXMLNode 添加一些有用的扩展,如下所示,

    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
        }
    }
    

    【讨论】:

    • 这让我走上了更好的道路。
    【解决方案2】:

    根据卡姆兰的回答,我得到了这个。

    
    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
            }
         }
    }
    

    好多了,但感觉还是松了。

    【讨论】:

      猜你喜欢
      • 2015-02-08
      • 1970-01-01
      • 2015-10-10
      • 1970-01-01
      • 2016-10-20
      • 1970-01-01
      • 2020-08-07
      • 1970-01-01
      • 2013-10-02
      相关资源
      最近更新 更多