如何在Swift字典中添加nil值?

85

我在我的应用程序中向服务器发出了请求,并发布了类似于这样的数据。服务器端等待所有参数,即使它们为空。但我无法将空值添加到字典中。

 var postDict = Dictionary<String,AnyObject>
 postDict[pass]=123
 postDict[name]="ali"
 postDict[surname]=nil // dictionary still has only pass and name variables.

有没有一种方法可以将 nil 值添加到字典中?


3
当您将nil赋值给一个键时,下次访问该键时它返回nil(因为它移除了对象并且被移除的对象不再存在)。如果要表示非nil的空值,可以使用NSNull() - The Paramagnetic Croissant
使用 [NSNull null] 或不使用。 - Jérôme Teisseire
这甚至不是一个关于Swift的问题;将NSNull实例放入字典中以表示空值是Foundation的一部分。 - Abizern
9个回答

133
如何向Swift字典中添加nil值?
基本上,您可以像添加其他任何值到字典一样添加nil值。您首先需要一个可以容纳该值的值类型字典。类型AnyObject不能具有值nil。因此,类型为[String : AnyObject]的字典不能具有值nil
如果您有一个值类型为可选类型的字典,例如[String : AnyObject?],那么它可以容纳nil值。例如:
let x : [String : AnyObject?] = ["foo" : nil]

如果您想使用下标语法来分配元素,那么这有点棘手。请注意,类型为[K:V]的下标具有类型V?。可选项是为了在取出时指示是否存在该键的条目,如果存在,则获取值; 在将其放入时,它允许您设置值或删除该条目(通过分配nil)。

这意味着对于我们的[String:AnyObject?]类型的字典,下标具有AnyObject??类型。同样,当您将一个值放入下标中时,"外部"可选项允许您设置一个值或删除该条目。如果我们简单地编写:

x["foo"] = nil
编译器推断这个值为nil,类型为AnyObject??,也就是说,需要移除键"foo"的条目。

为了将值"foo"设置为AnyObject?类型的nil,我们需要传入一个非nil的外部可选项,其中包含一个内部值为nil的可选项(类型为AnyObject?)。为此,我们可以执行以下操作:

let v : AnyObject? = nil
x["foo"] = v
或者
x["foo"] = nil as AnyObject?

任何表明我们拥有AnyObject?nil而不是AnyObject??的东西。


1
如果您将这个“Null”对象定义为常量,即static let NullObject: AnyObject?? = Optional(nil),那么使用起来会更加容易且可读性更高。 - Raginmari
16
将nil赋值给字典项表示删除该项,这个主意是谁想出来的?即使在字典定义为具有AnyObject? 或Any?类型的有效项时,nil也是一项有效的。这浪费了我几个小时的时间,也让我对Swift的看法下降了几个档次。 - RenniePet
2
正确答案是Guiller的答案,通过使用下标设置nil值,您可以删除值和键,而使用updateValue函数,您可以将值设置为nil同时保留键。 - Andrea
x["foo"] = nil 将删除条目 "foo"。x["foo"]! = nil 将把条目 "foo" 的值设置为 nil。x["bar"] = nil 不会插入任何条目。x["bar"]! = nil 会出错。x.updateValue(nil, forKey: "bar") 将添加条目 "bar" 到 x 中,其值为 nil,如 @Guiller 的答案所指出的那样。 - user2101384
x["foo"] = nil as Any? 也可以工作。但我认为对于初学者或刚开始使用 Swift 的人来说,updateValue(nil, forKey: "foo") 更容易理解。 - user2101384
显示剩余2条评论

58

您可以使用updateValue方法:

postDict.updateValue(nil, forKey: surname)

2
不知道为什么会被踩,但我认为这是最好的方法。 - ramazan polat
这是我在SA上见过的最好的答案。你应该被赠送100万瓶葡萄酒;)我已经创建了一份悬赏,并将在24小时内授予给你;) - Bartłomiej Semańczyk
@BartłomiejSemańczyk:那么您应该选择“一个或多个答案是值得额外赏金的典范。”作为悬赏原因。现在看起来好像您正在寻找另一个/更好的答案。 - Martin R
@MartinR 你说得对,我想改变赏金的原因,但我不能。这是一个很好的教训。;) - Bartłomiej Semańczyk

26
根据此处记录的内容,将字典中的键设为nil意味着删除该元素本身。 例如,如果要在转换为JSON时得到null,可以使用NSNull()
var postDict = Dictionary<String,AnyObject>()
postDict["pass"]=123
postDict["name"]="ali"
postDict["surname"]=NSNull()

let jsonData = NSJSONSerialization.dataWithJSONObject(postDict, options: NSJSONWritingOptions.allZeros, error: nil)!
let jsonString = NSString(data: jsonData, encoding: NSUTF8StringEncoding)!
// -> {"pass":123,"surname":null,"name":"ali"}

这应该是一个被接受的答案,因为传递 NSNull 不需要字典具有可选值。 - Roma Kavinskyi

5
postDict[surname] = Optional<AnyObject>(nil)

在大多数(所有?)情况下,您甚至不需要<AnyObject>。它应该能够推断出类型。 - Max

4
以下字典将保持一个键和空值。
var dict = [String:Any?]()
dict["someKey"] = nil as Any?

1
这是一个非常正确的答案,用于为键设置nil值。 - Li Jin

3
您可以使用“Optional”类型。
var postDict = ["pass": 123, "name": "ali", "surname": Optional()]

2
要将nil值添加到Swift字典中,您的字典值必须是Optional类型。
考虑一个Person类:
class Person {
    let name: String
    weak var spouse: Person?

    init(name: String, spouse: Person?) {
        self.name = name
        self.spouse = spouse
    }
}

Person 类型的实例可以有一个 name 和一个可选的 spouse。创建两个实例,并将第一个添加到字典中:

创建两个 `Person` 类型的实例,分别给它们命名并给其中一个实例设置配偶。然后将第一个实例添加到一个字典中。
let p1 = Person(name: "John", spouse: nil)
let p2 = Person(name: "Doe", spouse: p1)
p1.spouse = p2
var people = [p1.name: p1.spouse]

这个字典(称为people)将名字映射到配偶,并且是类型为[String: Person?]的。现在你有了一个值为Optional类型的字典:Person?

要将键p1.name的值更新为nil,请使用Dictionary类型的updateValue(_: forKey:)方法。

people.updateValue(nil, forKey: p1.name)
people[p1.name] 

p1.name 对应的值现在是 nil。在这种情况下,使用 updateValue(_: forKey:) 更加直接,因为它不涉及创建一个一次性实例,将其设置为 nil,然后将该实例分配给字典中的一个键。

NB: 有关向帖子字典中插入 null 的方法,请参见 rintaro 的答案。


2
var dict = [Int:Int?]()

dict[0] = (Int?).none // <--- sets to value nil

dict[0] = nil         // <-- removes

dict[0] = .none       // <-- same as previous, but more expressive

switch dict[0] {
case .none:
    Swift.print("Value does not exist")

case .some(let value):
    if let value = value {
        Swift.print("Value exists and is", value)
    } else {
        Swift.print("Value exists and is nil")
    }
}

var dict = Int: Int?。这是一个定义,而不仅仅是声明。 - Franklin Yu

1
postDict[surname]=nil

当您使用下标设置为nil时,如果键存在,则会删除该键。在这种情况下,如果存在键“surname”,则它将从字典中删除。
要将值设置为nil,有一些特定的方法。
postDict.updateValue(nil, forKey: surname)

或者

let anyObjectNil : AnyObject? = nil
postDict[surname] = anyObjectNil

或者

postDict[surname] = nil as AnyObject?

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接