Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/swift/20.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

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/url/2.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 在JSON解析中使用Decodable时,optional和decodeIfPresent之间有什么区别?_Swift_Swift4_Codable_Decodable - Fatal编程技术网

Swift 在JSON解析中使用Decodable时,optional和decodeIfPresent之间有什么区别?

Swift 在JSON解析中使用Decodable时,optional和decodeIfPresent之间有什么区别?,swift,swift4,codable,decodable,Swift,Swift4,Codable,Decodable,我第一次使用Swift 4中的Codable协议,我无法理解decodeIfPresent中的decodeIfPresent的用法 /// Decodes a value of the given type for the given key, if present. /// /// This method returns `nil` if the container does not have a value associated with `key`, or if the value is

我第一次使用Swift 4中的
Codable
协议,我无法理解
decodeIfPresent
中的
decodeIfPresent
的用法

/// Decodes a value of the given type for the given key, if present.
///
/// This method returns `nil` if the container does not have a value associated with `key`, or if the value is null. The difference between these states can be distinguished with a `contains(_:)` call.
///
/// - parameter type: The type of value to decode.
/// - parameter key: The key that the decoded value is associated with.
/// - returns: A decoded value of the requested type, or `nil` if the `Decoder` does not have an entry associated with the given key, or if the value is a null value.
/// - throws: `DecodingError.typeMismatch` if the encountered encoded value is not convertible to the requested type.
public func decodeIfPresent(_ type: String.Type, forKey key: KeyedDecodingContainer.Key) throws -> String?

在这里,它建议如果相关键不存在值,则返回
nil
。如果这是唯一的原因,那么它与可选属性有何不同,因为如果响应中不存在值,可选变量也会设置为
nil

是的,@Sweeper的评论很有道理

我会根据我的理解来解释

public class User : Decodable{

    public var firstName:String
    public var lastName:String
    public var middleName:String?
    public var address:String
    public var contactNumber:String


    public enum UserResponseKeys: String, CodingKey{
        case firstName = "first_name"
        case lastName = "last_name"
        case middleName = "middle_name"
        case address = "address"
        case contactNumber = "contact_number"
    }

    public required init(from decoder: Decoder) throws {

        let container = try decoder.container(keyedBy: UserResponseKeys.self)

        self.firstName = try container.decode(String.self, forKey: .firstName)
        self.lastName = try container.decode(String.self, forKey: .lastName)
        self.middleName = try container.decodeIfPresent(String.self, forKey: .middleName)
        self.address = try container.decode(String.self, forKey: .address)
        self.contactNumber = try container.decode(String.self, forKey: .contactNumber)
    }

}
上面是我的
User
类,其中我将
middleName
标记为可选参数,因为JSON响应可能不会在响应中提供
middleName
键值对,所以我们可以使用
decodeIfPresent

self.middleName = try container.decodeIfPresent(String.self, forKey: .middleName)
而对于其他属于必填字段的变量,我们确信不需要使用可选字段。我们只使用了
decode
,因为该方法不返回可选值

public func decode(_ type: String.Type, forKey key: KeyedDecodingContainer.Key) throws -> String
上面的
decode
函数返回
String
,而
decodeIfPresent
返回
String?
,因此我们可以使用可选变量来存储它


因此,最后的结论是,如果您不确定服务响应契约,或者您可能处理JSON响应和参数可能会在您不知情的情况下更改的任何第三方服务,那么您可以使用
decodeIfPresent
,以便它可以处理响应中缺少特定参数的情况,并将值设置为
nil

这两行代码之间有一个微妙但重要的区别:

//附件1
foo=try container.decode(Int?.self,forKey:.foo)
//附件2
foo=try container.decodeIfPresent(Int.self,forKey:.foo)
附件1将分析:

{
“foo”:空,
“酒吧”:“某物”
}
但是不是

{
“酒吧”:“某物”
}

而图表2将很高兴地解析这两个。因此,在
JSON
解析器的正常使用情况下,对于模型中的每个可选属性,您都需要
decodeIfPresent

我认为,如果您希望对JSON中可能缺少的属性使用默认值,那么使用
decodeIfPresent
而不是可选属性是有意义的

例如,让我们检查3种情况:

1。所有密钥都存在于JSON中:

{
    "project_names": ["project1", "project2", "project3"]
}
假设您必须解码此JSON:

{
    "project_names": ["project1", "project2", "project3"],
    "is_pro": true
}
您可以使用此结构:

struct Program: Codable {
    let projectNames: [String]
    let isPro: Bool
}
struct Program: Codable {
    let projectNames: [String]
    var isPro: Bool?
}
您将得到一个
Program
对象,其
isPro
值等于
true
。 (我假设您的解码器
keyDecodingStrategy
在本例的其余部分是
.convertFromSnakeCase


2。JSON中缺少一些键,您可以在Swift中使用可选键:

{
    "project_names": ["project1", "project2", "project3"]
}
现在可以使用此结构:

struct Program: Codable {
    let projectNames: [String]
    let isPro: Bool
}
struct Program: Codable {
    let projectNames: [String]
    var isPro: Bool?
}
您将得到一个
Program
对象,其
isPro
值等于
nil

如果JSON看起来像这样:

{
    "project_names": ["project1", "project2", "project3"],
    "is_pro": true
}
struct Program: Codable {
    let projectNames: [String]
    var isPro: Bool = false
}
然后,
isPro
将是一个值为
true的
Bool?
。 也许这就是您想要的,但您可能希望使用默认值为
false
Bool
。这就是
decodeIfPresent
可能有用的地方


3。JSON中缺少一些键,您需要一个在Swift中具有默认值的非可选属性:

{
    "project_names": ["project1", "project2", "project3"]
}
如果您的结构如下所示:

{
    "project_names": ["project1", "project2", "project3"],
    "is_pro": true
}
struct Program: Codable {
    let projectNames: [String]
    var isPro: Bool = false
}
如果JSON中不存在“is_pro”属性,则会出现解析错误因为Codable希望找到一个值来解析Bool属性。

在这种情况下,一个好主意是使用带有
decodeIfPresent
的初始值设定项,如下所示:

struct Program: Codable {
    let projectNames: [String]
    let isPro: Bool

    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        self.projectNames = try container.decode([String].self, forKey: .projectNames)
        self.isPro = try container.decodeIfPresent(Bool.self, forKey: .isPro) ?? false
    }
}
这使您能够在两个方面都做到最好:

  • 您的结构具有
    Bool
    ,而不是
    Bool?
    属性
  • 您仍然能够解析不包含“is_pro”字段的JSON
  • 如果JSON中不存在该字段,则可以获得默认值
    false

您是否知道该方法返回一个可选的
字符串?
?所以基本上你是对的。有一个选项的使用。找到答案:虽然在文档中没有提到。在问题D中也可以找到它本身。如果遇到的编码值不能转换为请求的类型,它将抛出
DecodingError.typeMismatch
解码
也会抛出三种不同的错误。请参见第一个响应能否由
foo=try container.decode(Int.self,forKey.foo)
解析?否,它不能用
foo=try container.decode(Int.self,forKey.foo)
解析,因为
Int
不能保存
null
值(即
nil
)。在
foo=try container.decodeIfPresent(Int.self,forKey.foo)
foo=try之间是否存在差异?container.decode(Int.self,forKey.foo)
?是的,因为
foo=try?container.decode(Int.self,forKey.foo)
将对
中“foo”
包含值但无法转换为
Int
的所有事件进行解码。例如:
“foo”:“某物”
将导致
foo
包含
nil
。您肯定应该捕获错误,而不是通过
try?
忽略它。