如何在Swift 3中将NSData转换为Data?

12

我正在尝试创建一个简单的天气应用程序,该应用程序获取用户的位置并使用Google Maps API显示简单的天气数据。除了这一部分,即我获取JSON并获得地址之外,一切都正常。

func getAddressForLatLng(latitude: String, longitude: String) {
    let url = NSURL(string: "\(baseUrl)latlng=\(latitude),\(longitude)&key=\(apikey)")
    let data = NSData(contentsOf: url! as URL)
    let json = try! JSONSerialization.jsonObject(with: data, options: JSONSerialization.ReadingOptions.allowFragments) as! Dictionary
    if let result = json["results"] as? Dictionary {
        if let address = result[0]["address_components"] as? Array {
            let number = address[0]["short_name"] as! String
            let street = address[1]["short_name"] as! String
            let city = address[2]["short_name"] as! String
            let state = address[4]["short_name"] as! String
            let zip = address[6]["short_name"] as! String
            weatherDisplay.text = "\(city),\(state)"
        }
    }
}

在线上:

let json = try! JSONSerialization.jsonObject(with: data, options: JSONSerialization.ReadingOptions.allowFragments) as! Dictionary 

我遇到了这个错误:

Cannot invoke 'jsonObject' with an argument list of type '(with: NSData?, options: JSONSerialization.ReadingOptions)'

我做错了什么?


5
这里完全不需要使用NSData(或NSURL)。可以使用let url = URL(string: ...)let data = Data(contentsOf: ...)来代替。 - Martin R
问题在于你把一个可选值传递给了 JSONSerialization 。你可以强制解包数据,例如 JSONSerialization.jsonObject(with: data!, options: JSONSerialization.ReadingOptions.allowFragments) as! Dictionary - Luke Van In
2
请注意,使用NSData(contentsOf: url! as URL)(或在Swift 3中使用Data(contentsOf:))是不好的做法。这是一个同步调用,并且会冻结UI,直到完成为止。您真的应该重写它以使用NSURLSession。 - Duncan C
2
我很难理解为什么这个问题被投票否决了。看起来是一个合法的问题,完全在集合和相关标签的范围内。 - Caleb
@LukeVanIn 为什么要使用allowFragments?而且你知道强制解包会在下载失败时崩溃吗? - gnasher729
gnasher729 这个问题有很多问题,我的评论旨在解决错误,而不是尝试纠正所有其他问题。问题不在于 NSData 需要转换为 Data,而是对象需要被解包。强制解包数据会导致崩溃,正如你正确指出的那样,尽管代码在其他地方使用了强制解包也会崩溃。我使用 allowFragments 是因为这是问题所使用的。通常情况下不需要这样做,因为大多数 JSON 将是一个对象或一个数组。 - Luke Van In
3个回答

31

9
您需要进行一些更改。首先,您正在使用NSData,您应该使用Swift类型Data。要从NSData?转换为Data?,只需在变量声明的末尾添加as Data?即可。
此外,您的类型是可选的,但您无法传递可选类型,因此您需要对其进行解包(在本例中使用if let data = data { /* stuff here */}):
func getAddressForLatLng(latitude: String, longitude: String) {
    let url = NSURL(string: "\(baseUrl)latlng=\(latitude),\(longitude)&key=\(apikey)")
    let data = NSData(contentsOf: url! as URL) as Data? // <==== Added 'as Data?'
    if let data = data { // <====== Added 'if let'
        let json = try! JSONSerialization.jsonObject(with: data, options: JSONSerialization.ReadingOptions.allowFragments) as! Dictionary
        if let result = json["results"] as? Dictionary {
            if let address = result[0]["address_components"] as? Array {
                let number = address[0]["short_name"] as! String
                let street = address[1]["short_name"] as! String
                let city = address[2]["short_name"] as! String
                let state = address[4]["short_name"] as! String
                let zip = address[6]["short_name"] as! String
                weatherDisplay.text = "\(city),\(state)"
            }
        }
    }
}

更新:

你需要改变的另一件事是:

let json = try! JSONSerialization.jsonObject(with: data, options: JSONSerialization.ReadingOptions.allowFragments) as! Dictionary

当您将类型转换为Dictionary时,编译器并不知道您在说什么,因为Dictionary是一种泛型类型。因此,您需要将其转换为Dictionary<String,AnyObject>[String:AnyObject](它们是相同的)。

感谢您的快速回复!现在它显示(在let = json行上):“无法推断泛型参数'key'在转换为'Dictionary<_,_>'中。” - Eric Phillips
@EricPhillips,我更新了我的回答! - Caleb Kleveter
现在,在这一行 if let address = result[0]["address_components"] as? Array { 上,它显示“模糊的成员引用'subscript'”。我需要添加或更改其他内容吗? - Eric Phillips
@EricPhillips 不太确定。我知道 Array 类型就像 Dictionary 类型一样。你需要添加数组的类型,例如 Array<String>。如果你有更多问题,建议先在 Google 上搜索,然后在 SO(Stack Overflow)上提出新问题。 - Caleb Kleveter

1
只需要这样写:let newData = nsData as Data

这不就是在被接受的答案中添加了as Data?let data = NSData(contentsOf: url! as URL) as Data? // <==== Added 'as Data?'所做的吗? - Wai Ha Lee

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