【问题标题】:Reading countries names from JSON file problem从 JSON 文件问题中读取国家名称
【发布时间】:2018-10-19 16:20:13
【问题描述】:

我正在尝试使用 swift 从 json 文件中加载和解析国家名称,但我不能

这是我尝试读取的文件格式:Countries JSON File

我执行此任务的代码:

func getJsonFromUrl(){
    let url = NSURL(string: COUNTRIES_URL)
    URLSession.shared.dataTask(with: (url as URL?)!, completionHandler: {(data, response, error) -> Void in
        if let jsonObj = try? JSONSerialization.jsonObject(with: data!, options: .allowFragments) as? NSDictionary {
            if let countries_array = jsonObj!.value(forKey: "name") as? NSArray {
                for country in countries_array {
                    if let countryDict = country as? NSDictionary {
                        if let name = countryDict.value(forKey: "name") {
                            self.countries_names.append((name as? String)!)
                        }
                    }
                }
            }
            OperationQueue.main.addOperation ({
                self.showNames()
            })
        }
    }).resume()
}

但是当我运行它时,它在这一行给我一个错误: if let countries_array = jsonObj!.value(forKey: "name") as? NSArray { 因为意外的 nil。

【问题讨论】:

  • 你的if let jsonObj = try? JSONSerialization.jsonObject(with: data!, options: .allowFragments) as? NSDictionary { 应该是as? Array<[String: Any]>,因为最上面的对象实际上是一个数组

标签: ios json swift xcode


【解决方案1】:

JSON 以方括号 ([) 开头,因此根对象是一个数组

不要在 Swift 中使用 NSURLNSArrayNSDictionaryvalue(forKey

并处理可能的错误。

func getJsonFromUrl() {
    let url = URL(string: COUNTRIES_URL)!
    URLSession.shared.dataTask(with: url!, completionHandler: {(data, response, error) -> Void in
        if let error = error { print(error); return }
        do {
            if let countriesArray = try JSONSerialization.jsonObject(with: data!) as? [[String:String]] {
                for country in countriesArray {
                    self.countries_names.append(country["name"]!)
                }
            }
        } catch { print(error) }
        OperationQueue.main.addOperation ({
            self.showNames()
        })
    }).resume()
}

或者使用Decodable 更方便

struct Country : Decodable {
    let name : String
}

func getJsonFromUrl() {
    let url = URL(string: COUNTRIES_URL)!
    URLSession.shared.dataTask(with: url!, completionHandler: {(data, response, error) -> Void in
        if let error = error { print(error); return }
        do {
            let countries = try JSONDecoder().decode([Country].self, from: data!)
            self.countries_names = countries.map{$0.name}
        } catch { print(error) }
        OperationQueue.main.addOperation ({
            self.showNames()
        })
    }).resume()
}

【讨论】:

  • 也尽量不要使用强制展开
  • @AdityaSrivastava 在这种情况下,一切都非常安全。 URL 字符串是一个常量,data 如果errornil 并且JSON 一致,则data 有效。您甚至可以强制将向下转换为 [[String:String]]
【解决方案2】:

你需要的是数组而不是字典

if let dat = data {
   if let jsonObj = try? JSONSerialization.jsonObject(with: dat, options:[]) as? [[String:String]]{
   jsonObj.forEach { print($0["name"]) }    
}

或使用Codable

let res = try? JSONDecoder().decode([[String:String]].self,from:data)

或与模型

struct Root: Codable {
  let name : String
}

let res = try? JSONDecoder().decode([Root].self,from:data)

【讨论】:

    猜你喜欢
    • 2016-06-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-11-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多