简体   繁体   English

Swift 来自 XML 的可失败初始化程序

[英]Swift Failable initializer from XML

Let me start by saying what I have works...让我先说我有什么作品......

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

I am not happy with it.我对此不满意。 I can simplify by doing null check and reusing a temporary variable我可以通过进行 null 检查和重用临时变量来简化

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

Ideally I want to be able to assign the properties as I check them without going through some sort of temporary variable.理想情况下,我希望能够在检查属性时分配属性,而无需通过某种临时变量。

something like:就像是:

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

This errors with use of self without initializing all stored properties.在未初始化所有存储属性的情况下使用 self 时会出现此错误。

Is there a better way to do it?有更好的方法吗?

I would suggest adding some helpful extensions to XMLDocument and XMLNode as below,我建议为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
    }
}

So, now your struct will look like this,所以,现在你的结构看起来像这样,

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

building off of Kamran's answer I got this.根据卡姆兰的回答,我得到了这个。


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

which pretties my initializer to这让我的初始化程序很漂亮

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

Much better, but it still feels loose.好多了,但感觉还是松了。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 Swift:从抛出初始化程序调用可失败初始化程序? - Swift: calling failable initializer from throwing initializer? 为Swift覆盖失败的初始化程序 - Overriding a Failable Initializer for Swift SwiftyJSON的Swift失败初始化器 - Swift Failable Initializer with SwiftyJSON Swift:使用Failable Initializer从JSON创建模型类 - Swift: Creating Model Class from JSON with Failable Initializer 为什么不能使用if语法在初始化器中从子类的非失败初始化器中调用失败的初始化器? [迅速] - why is it not possible to use if let syntax in an initializer to call a failable initializer from a subclass’s nonfailable initializer? [swift] singleton class 中的可失败初始化与 swift 中的私有初始化程序 - failable init in singleton class with private initializer in swift 在 Swift 中实现可失败初始化程序的最佳实践 - Best practice to implement a failable initializer in Swift Swift Failable Initializer无法返回Nil? - Swift Failable Initializer Can’t Return Nil? 如何防止Swift枚举的可初始化失败器在原始数字范围内返回nil? - How to prevent a failable initializer of a Swift enum from returning nil within a range of raw numbers? Swift:“failable initializer'init()'不能覆盖不可用的初始化程序”与默认参数 - Swift: “failable initializer 'init()' cannot override a non-failable initializer” vs. default parameters
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM