This is the 18th day of my participation in Gwen Challenge
Here’s what I learned from reading [SwiftyJSON] source code.
Other articles
SwiftyJSON (1)
Literal conversion
In SwiftyJSON, there are rich initialization methods for JSON that can be used to quickly create a JSON literal. Such as:
let json = JSON(12345)
let json = JSON(["name"."age"])
let json = JSON(["name":"Jack"."age": 25])
Copy the code
Swift provides a very interesting set of interfaces for converting literals to corresponding types. After these conversion interfaces are implemented, it is easy to convert to the corresponding type by way of assignment. Literal conversion interfaces all define a TypeAlias and the corresponding init method.
Frequently used interfaces are:
- ExpressibleByStringLiteral: one definition
public typealias StringLiteralType = String
, and the corresponding init method. - ExpressibleByArrayLiteral
- ExpressibleByBooleanLiteral
- ExpressibleByDictionaryLiteral
- ExpressibleByFloatLiteral
- ExpressibleByNilLiteral
- ExpressibleByIntegerLiteral
For more on literal conversions, I recommend reading Wang Wei’s article: Literal conversions, which have some outdated content, but still have a lot to learn.
Literal conversions are a double-edged sword. They can shorten the code and simplify the meaning, but at the same time, the lack of an obvious initialization function can confuse others and make it impossible to quickly jump to the corresponding initialization method via CMD + click.
How do I add nil values to a Swift dictionary
It’s strange to see this code in SwiftyJSON:
guard let dict = object as? [String: Any?] else {
return nil
}
let body = try dict.keys.map { key throws -> String in
guard let value = dict[key] else {
return "\"\(key)\": null"
}
guard let unwrappedValue = value else {
return "\"\(key)\": null"
}
let nestedValue = JSON(unwrappedValue)
/ /...
}
Copy the code
[String: Any?] Do I need to unpack the key twice to obtain the value of a key in the dictionary of type? Can value be nil? When you assign a key to nil, doesn’t that just erase the key?
Take a look at the following code:
let value: Any? = nil
var dict = [String: Any?]()
dict["key"] = value
debugPrint(dict)
// output: ["key": nil]
Copy the code
Indeed as expected/String: Any? The value in the dictionary of a type can be null. Let’s look at the code below. It’s not true that any key assigned to nil can be stored in a dictionary.
let aKey = "aKey"
var dict = [String: Any?] ()let value: String? = nil
dict[aKey] = value
debugPrint(dict)
// Output: [:]
dict[aKey] = value as Any?
debugPrint(dict)
// output: ["aKey": nil]
Copy the code
Only value can be Any? Type is saved in the dictionary.
How do I add nil to a Swift dictionary?
Method 1: Match the corresponding type
The same way you would add any other type of value to a dictionary. But make sure the dictionary can hold the corresponding value type. For a dictionary whose value type is optional, such as [String: Any? , so it can hold nil values. For example,
let x : [String : AnyObject? ]= ["foo" : nil]
Copy the code
Note that a [K:V] dictionary, when accessed by subscript, returns an optional V? , optional indicates whether there is a value corresponding to the key. If there is a value, the corresponding value is returned. When setting a value by subscripting, you can set a value or delete an entry by setting nil.
Therefore, for [String: Any? A dictionary of type. The type returned by subscript is Any?? . Similarly, when putting values into subscripts, external options allow you to set values or delete entries (external options are Any?? The second?) . If we simply write:
x["foo"] = nil
Copy the code
The compiler concludes that it is Any?? Type nil, externally optional means deleting the entry for key foo.
To set the value of the key foo to Any? Nil, we need to pass in an external alternative that is not nil, that is, an internal alternative containing a value of nil (Any? Type). In response, we can do the following:
let v: Any? = nil
x["foo"] = v
Copy the code
or
x["foo"] = nil as Any?
Copy the code
That means set it to Any, okay? Nil instead of Any? .
Method 2: updateValue
Alternatively, you can add nil values to the dictionary using the updateValue method:
var dic = [String: Any?]()
dic.updateValue(nil, forKey: "foo")
debugPrint(dic)
// Output: ["foo": nil]
Copy the code
Method 3: NSNull
Can we use NSNull to set nil? Here’s using NSNull and using Any? Code comparison.
Code for using NSNull:
let aKey = "aKey"
var dict = [String: Any?]()
dict[aKey] = NSNull(a)debugPrint(dict)
// Output: ["aKey": Optional(
)]
debugPrint(type(of: dict[aKey]))
Swift.Optional
>
if dict[aKey] is NSNull {
debugPrint("value is NSNull")}else {
debugPrint("value is not NSNull")}// Output: value is NSNull
if let value: Any? = dict[aKey] {
debugPrint("value is \(value)")
// Output: value is Optional(
)
if let unwrappedValue = value {
debugPrint("unwrappedValue is \(unwrappedValue)")}else {
debugPrint("has no corresponding unwrappedValue")}UnwrappedValue is
}
Copy the code
Code that uses nil:
let aKey = "aKey"
var dict = [String: Any?] ()let value2: Any? = nil
dict[aKey] = value2
debugPrint(dict)
// output: ["aKey": nil]
debugPrint(type(of: dict[aKey]))
Swift.Optional
>
if dict[aKey] is NSNull {
debugPrint("value is NSNull")}else {
debugPrint("value is not NSNull")}// Output: value is not NSNull
if let value: Any? = dict[aKey] {
debugPrint("value is \(value)")
// Output: value is nil
if let unwrappedValue = value {
debugPrint("unwrappedValue is \(unwrappedValue)")}else {
debugPrint("has no corresponding unwrappedValue")}Has no corresponding unwrappedValue
}
Copy the code
Compare the two pieces of code above, NSNull and Any? It’s not consistent. When using NSNull, the final NSNull object is obtained using Any? , gets nil.
This is not recommended because if you use NSNull, you will also need to treat the existing NSNull object as nonexistent (as if the saved object is nil) when determining whether it has a value.
reference
How to add nil value to Swift Dictionary?