Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/swift/18.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Swift 有没有办法更简洁地使用守卫声明?_Swift - Fatal编程技术网

Swift 有没有办法更简洁地使用守卫声明?

Swift 有没有办法更简洁地使用守卫声明?,swift,Swift,我正在使用它进行JSON实例化。下面是一个示例类: public class MyObj: Decodable { let id_user : String let contact_addr1 : String let contact_addr2 : String? let contact_city : String let contact_state : String let contact_zip :

我正在使用它进行JSON实例化。下面是一个示例类:

public class MyObj: Decodable
{
    let id_user         : String
    let contact_addr1   : String
    let contact_addr2   : String?
    let contact_city    : String
    let contact_state   : String
    let contact_zip     : String
    let points          : Int

    // Deserialization
    required public init?(json: JSON)
    {
        guard let id_user : String = "somekey" <~~ json else {
            assertionFailure("MyObj - invalid JSON. Missing key: wouldbenicetonotwritethisforeachmember")
            return nil
        }
        guard let contact_addr1 : String = "somekey" <~~ json else {
            assertionFailure("MyObj - invalid JSON. Missing key: wouldbenicetonotwritethisforeachmember")
            return nil
        }
        guard let contact_city : String = "somekey" <~~ json else {
            assertionFailure("MyObj - invalid JSON. Missing key: wouldbenicetonotwritethisforeachmember")
            return nil
        }
        guard let contact_state : String = "somekey" <~~ json else {
            assertionFailure("MyObj - invalid JSON. Missing key: wouldbenicetonotwritethisforeachmember")
            return nil
        }
        guard let contact_zip : String = "somekey" <~~ json else {
            assertionFailure("MyObj - invalid JSON. Missing key: wouldbenicetonotwritethisforeachmember")
            return nil
        }
        guard let points : Int = "somekey" <~~ json else {
            assertionFailure("MyObj - invalid JSON. Missing key: wouldbenicetonotwritethisforeachmember")
            return nil
        }

        self.id_user        = id_user
        self.contact_addr1  = contact_addr1
        self.contact_addr2  = "somekey"     <~~ json
        self.contact_city   = contact_city
        self.contact_state  = contact_state
        self.contact_zip    = contact_zip
        self.contact_points = points
    }
}

也许有一种方法可以防止字符串键数组的出现?

实现这一点的方法有很多种。它们都归结为编写一个包装器函数来将键映射到值。下面是我想到的几个快速示例,但正如我所说的,根据您的目标,有很多方法可以做到这一点:

enum JSONError: Error {
    case keyNotFound(String)
}

extension JSON {
    func values<T>(for keys: [String]) throws -> [T] {
        var values = [T]()

        for key in keys {
            guard let value: T = key <~~ self else {
                throw JSONError.keyNotFound(key)
            }

            values.append(value)
        }

        return values
    }

    func values<T>(for keys: [String], closure: ((_ key: String, _ value: T) -> Void)) throws {
        for key in keys {
            guard let value: T = key <~~ self else {
                throw JSONError.keyNotFound(key)
            }

            closure(key, value)
        }
    }
}
第二个将把键、值对传回到一个闭包,因为它们出现在您的键数组中,并将抛出它发现的第一个不存在的闭包

do {
    let keys = ["foo", "bar"]

    // The type of the closure's value argument is important.
    // In this example we're saying look for values of type String.
    try json.values(for: keys) { (key, value: String) in
        print("value for key \(key) is \(value)")
    }
} catch JSONError.keyNotFound(let key) {
    assertionFailure("key not found \(key)")
}
在类的
init?()
函数中使用第一个版本,我们有如下内容:

public struct MyObj: Decodable {
    public let id_user         : String
    public let contact_addr1   : String
    public let contact_addr2   : String?
    public let points          : Int

    public init?(json: S) {
        do {
            let stringKeys = ["id_user", "contact_addr1"]
            let stringValues: [String] = try json.values(for: stringKeys)

            id_user = stringValues[0]
            contact_addr1 = stringValues[1]

            // this isn't required, so just extract with no error if it fails
            contact_addr2 = "contact_addr2" <~~ json

            let intKeys = ["points"]
            let intValues: [Int] = try json.values(for: intKeys)

            points = intValues[0]
        } catch JSONError.keyNotFound(let key) {
            assertionFailure("key \(key) not found in JSON")
            return nil
        } catch {
            return nil
        }
    }
}
公共结构MyObj:可解码{
公共let id\u用户:字符串
public let contact_addr1:字符串
public let contact_addr2:字符串?
公共出租点:Int
public init?(json:S){
做{
让stringKeys=[“id\u user”,“contact\u addr1”]
让stringValues:[String]=尝试json.values(for:stringKeys)
id\u user=stringValues[0]
联系人地址1=stringValues[1]
//这不是必需的,所以如果失败,只需无错误地提取即可

contact_addr2=“contact_addr2”我没有使用Gloss,而且考虑到它足够简单,可以安全地解析JSON,而不需要额外的库,也不需要使用不熟悉的语法,所以它似乎没有必要

选项1:

您可以在单个
guard
语句中对可选展开进行分组

例如:

public struct MyObj {
    let id_user         : String
    let contact_addr1   : String
    let contact_addr2   : String?
    let points          : Int

    public init?(json: Any) {
        guard 
            let entities = json as? [String : Any],
            let id_user = entities["some key"] as? String,
            let contact_addr1 = entities["some key"] as? String,
            let points = entities["some key"] as? Int
        else {
            assertionFailure("...")
            return nil
        }

        self.id_user        = id_user
        self.contact_addr1  = contact_addr1
        self.contact_addr2  = entities["some key"] as? String
        self.contact_points = points
    }
}
// Helper object for parsing values from a dictionary. 
// A similar pattern could be used for arrays. i.e. array.stringAt(10)
struct JSONDictionary {
    let values: [String : Any]
    init(_ json: Any) throws {
        guard let values = json as? [String : Any] else {
            throw MyError.expectedDictionary
        }
        self.values = values
    }

    func string(_ key: String) throws -> String {
        guard let value = values[key] as? String else {
            throw MyError.expectedString(key)
        }
        return value
    }

    func integer(_ key: String) throws -> Int {
        guard let value = values[key] as? Int else {
            throw MyError.expectedInteger(key)
        }
        return value
    }
}
选项2:

另一种方法是完全消除
guard
语句,让解析器在解析过程中抛出错误,并使用可选的
try
将结果转换为nil

例如:

public struct MyObj {
    let id_user         : String
    let contact_addr1   : String
    let contact_addr2   : String?
    let points          : Int

    public init?(json: Any) {
        guard 
            let entities = json as? [String : Any],
            let id_user = entities["some key"] as? String,
            let contact_addr1 = entities["some key"] as? String,
            let points = entities["some key"] as? Int
        else {
            assertionFailure("...")
            return nil
        }

        self.id_user        = id_user
        self.contact_addr1  = contact_addr1
        self.contact_addr2  = entities["some key"] as? String
        self.contact_points = points
    }
}
// Helper object for parsing values from a dictionary. 
// A similar pattern could be used for arrays. i.e. array.stringAt(10)
struct JSONDictionary {
    let values: [String : Any]
    init(_ json: Any) throws {
        guard let values = json as? [String : Any] else {
            throw MyError.expectedDictionary
        }
        self.values = values
    }

    func string(_ key: String) throws -> String {
        guard let value = values[key] as? String else {
            throw MyError.expectedString(key)
        }
        return value
    }

    func integer(_ key: String) throws -> Int {
        guard let value = values[key] as? Int else {
            throw MyError.expectedInteger(key)
        }
        return value
    }
}
解析器:

public struct MyObj {
    let id_user         : String
    let contact_addr1   : String
    let contact_addr2   : String?
    let points          : Int

    public init(json: Any) throws {
        // Instantiate the helper object. 
        // Ideally the JSONDictionary would be passed by the caller.
        let dictionary = try JSONDictionary(json),
        self.id_user = try dictionary.string("some key"),
        self.contact_addr1 = try dictionary.string("some key"),
        self.points = try dictionary.integer("some key")

        // Results in an optional if the string call throws an exception
        self.contact_addr2 = try? dictionary.string("some key")
    }
}
用法:

// Instantiate MyObj from myJSON. 
// myObject will be nil if parsing fails.
let myObject = try? MyObj(json: myJSON)

关于使用gloss。你应该阅读本文的最后一段,应该使用结构而不是类,并花一些时间为你的结构创建自定义初始值设定项,而不是使用gloss。你应该看看这一点。很多人喜欢对Swift过于冗长但几乎不可读的默认实现进行一些抽象。我想t以避免十亿个x作为?[String:Any]保护语句。空合并运算符(??)允许我非常简洁地执行我想要的操作,但它不允许我在缺少密钥时执行任何错误处理(这在开发过程中会很有帮助)。“…更喜欢一点抽象,而不是Swift过于冗长的…”.对不起,这引起了我的注意。你和Objective-C合作过很多吗?有些东西在Swift上不是“开箱即用”的,无论是版本2、版本3,甚至版本4。据说,这可能是我第一次听到“Swift”和“冗长”在同一句话中::-)是的,尽管Swift的使命声明,Obj-C实际上不那么冗长,也更容易阅读,因为选项太乱了。如果你想辩论,请在适当的论坛上发表文章。你必须在这里回答我原来的问题。现在这就是我要说的。请给我一分钟时间回顾一下。类型是凝灰岩对我来说是新事物。当示例1中的
guard
出现故障时,您无法判断哪个键是故障点,这有点限制。在示例2中,您的
string()
integer()
函数是很好的例子,但不应隐式返回未包装的选项。只需分别返回
String
Int