Ios Swift选项:语言问题,还是做错了什么?

Ios Swift选项:语言问题,还是做错了什么?,ios,swift,Ios,Swift,我正在做我认为非常简单的事情。如果键存在,我试图从字典中获取一个值。我对字典中的几个键执行此操作,然后创建一个对象(如果它们都存在的话)(基本上是解码JSON对象)。我对这门语言还不熟悉,但在我看来,这门语言应该有用,但却不能: class func fromDict(d: [String : AnyObject]!) -> Todo? { let title = d["title"]? as? String // etc... } 它给了我一个错误:后缀的操作数?应具有

我正在做我认为非常简单的事情。如果键存在,我试图从字典中获取一个值。我对字典中的几个键执行此操作,然后创建一个对象(如果它们都存在的话)(基本上是解码JSON对象)。我对这门语言还不熟悉,但在我看来,这门语言应该有用,但却不能:

class func fromDict(d: [String : AnyObject]!) -> Todo? {
    let title = d["title"]? as? String
    // etc...
}
它给了我一个错误:
后缀的操作数?应具有可选类型;类型为(字符串,任意对象)

但是,如果我这样做,它会起作用:

class func fromDict(d: [String : AnyObject]!) -> Todo? {
    let maybeTitle = d["title"]?
    let title = maybeTitle as? String
    // etc...
}

这似乎是基本的替代,但我可能遗漏了语言的一些细微差别。有人能解释一下吗?

推荐的模式是

if let maybeTitle = d["title"] as? String {
    // do something with maybeTitle
}
else {
    // abort object creation
}
这可能真的是一个细微差别的问题。格式
数组[下标]?
不明确,因为它可能意味着整个字典(
)是可选的,而您可能指的是结果(
字符串
)。在上面的模式中,您利用了这样一个事实,即
字典
被设计为假设访问某些键会导致可选类型

经过实验,并注意到
之后的
一样不明确,更重要的是,我的解决方案如下:

var dictionary = ["one":"1", "two":"2"]
// or var dictionary = ["one":1, "two":2]
var message = ""
if let three =  dictionary["three"] as Any? {
    message = "\(three)"
}
else {
    message = "No three available."
}
message // "No three available."
这将适用于所有非对象Swift对象,包括Swift字符串、数字等。感谢Viktor提醒我
String
不是Swift中的对象+


如果您知道值的类型,可以使用适当的可选类型替换
Any?
,例如
String?

这里有一些事情

1)
d[“title”]?
中的
用法不正确。如果您试图展开
d[“title”]
,请使用
但要小心,因为如果
title
不是字典中的有效键,则会崩溃。(
用于可选链接,就像您试图对可选变量调用方法或访问属性一样。在这种情况下,如果可选变量为
nil
,则访问将不起任何作用)。您似乎没有试图打开
d[“title”]
,因此请关闭
。字典访问总是返回可选值,因为键可能不存在

2) 如果要解决此问题:

let maybeTitle = d["title"] as? String
错误消息更改为:错误:“(字符串,任意对象)”不能转换为“字符串”

这里的问题是
字符串
不是对象。您需要强制转换到
NSString

let maybeTitle = d["title"] as? NSString
这将导致
maybeTitle
成为
NSString?
。如果
d[“title”]
不存在,或者如果类型确实是
NSNumber
而不是
NSString
,则可选值将为
nil
,但应用程序不会崩溃

3) 你的声明:

let title = maybeTitle as? String
不按您的意愿展开可选变量。正确的形式是:

if let title = maybeTitle as? String {
    // title is unwrapped and now has type String
}
因此,把所有这些放在一起:

if let title = d["title"] as? NSString {
    // If we get here we know "title" is a valid key in the dictionary, and
    // we got the type right.  title has now been unwrapped and is ready to use
}
title
将具有类型
NSString
,该类型存储在字典中,因为它包含对象。您可以使用
NSString
执行您可以使用
String
执行的大部分操作,但是如果您需要
title
成为
字符串,您可以执行以下操作:

if var title:String = d["title"] as? NSString {
    title += " by Poe"
}
如果您的词典也有
NSNumber
s:

if var age:Int = d["age"] as? NSNumber {
    age += 1
}

因为NSString和String之间有自动转换;您正在将NSString保存为字符串而不强制转换。如果需要字符串,那么使用NSString只会让人感到困惑。遗憾的是,我们不得不使用
NSString
,但在处理来自Cocoa和Cocoa touch调用的词典时,这是事实。如果字典是
[String:Any]
的话,生活就会简单得多。因为每个NSObject都有一个可选的NSString,所以没有必要使用
As而不是
As
As?
允许应用程序在字典没有我们期望的类型的情况下生存。当值实际为
NSNumber
时,强制转换为
NSString
将导致崩溃。如果字典来自外部源,那么假设您知道值的类型是什么是很危险的。请在操场上尝试此代码。然后将23更改为字符串<代码>变量d:[字符串:AnyObject]!=[“name”:“Fred”,“age”:23]如果让age:String=d[“age”]as?NSString{println(“age是一个字符串”)}如果让age:Int=d[“age”]as?NSNumber{println(“age是一个Int”)}
d[“title”]
是可选的,您在可选错误后使用
。这个操作符的一个用例是
object?.property
,因此它只会计算
object.property
,当
object
不是
nil
时,它会返回
nil
,我也这么认为,但这会在操场上抛出一个错误,就像@vacawama提到的那样。字典中的
NSString
作为值显示为
(String,AnyType)
的一种类型,不能在同一行中转换为
String?
。。。你的maybeTitle将不再是maybe,否则它将不会在进入if括号之前被正确设置。如果字典的类型是
[String:AnyObject]就像OP的字典一样。这对我来说在操场上不起作用。
如果让三个=字典[“三”]作为NSObject?
如果字典是
[String:AnyObject]。是的,这是类似的解决方案。