【问题标题】:SWIFT: Storing JSON Data in An ArraySWIFT:将 JSON 数据存储在数组中
【发布时间】:2020-06-10 18:18:08
【问题描述】:

我有以下 JSON 格式的数据:

{"contacts":[{"name":"Bob"},{"name":"Greg"},{"name":"Sally"},{"name":"Will"},{"name":"George"},
{"name":"Charlie"},{"name":"Alice"},{"name":"Albert"},{"name":"Alfred"},{"name":"Bart"}, 
{"name":"Dan"},{"name":"Dave"},{"name":"Eddie"},{"name":"Frank"},{"name":"Ralph"},{"name":"Tammy"}, 
{"name":"Tom"},{"name":"James"},{"name":"John"},{"name":"Quincy"},{"name":"Peter"},{"name":"Richard"}, 
{"name":"Zachary"},{"name":"Zbiginew"},{"name":"Tentacool"},{"name":"Tentacruel"},{"name":"Metapod"}, 
{"name":"Meowth"}]}

JSON 存储在某个 URL 中,我想收集信息并将其放入一个数组中,理想情况下看起来像 [Bob, Greg, Sally, Will...]

现在我得到了代码:

let jsonLocation = "http://raw.myjsondatalocation.com/contact.json"
        guard let url = URL(string: jsonLocation) else {
            return
        }

        URLSession.shared.dataTask(with: url){ (data,response,error) in
            guard let data = data else { return }
            do{
                let decoder = JSONDecoder()
                let ListOfNames = try decoder.decode(Contact.self, from:data).contacts
                // print(myListOfContacts)
                print(ListOfNames[0].name)
            }
            catch let jsonErr{
                print("Error!",jsonErr)
            }
            }.resume()

我使用 Codable 来解析 JSON。这似乎工作正常,因为它返回一个表单为[[ContactList.Contact.PersonalInfo(name: "Bob")... 的项目数组,当我调用print(ListOfNames[0].name) 时,它适当地返回“Bob”,但如果我把它放在 URLSession 之外,它说它没有解决。

名称数组稍后将被放入 TableView。我真的不知道如何解决这个问题。有人可以帮我看看吗?

【问题讨论】:

  • URLSession 块之外将listOfNames 属性声明为var。然后在你使用listOfNames = try decoder ...的块内。请注意,根据 Swift 约定,属性名称以小写字母开头。
  • 不要将结构数组映射到字符串数组。使用PersonalInfo 作为数据源数组。也许您想在将来添加更多个人信息
  • 这能回答你的问题吗? Returning data from async call in Swift function

标签: json swift parsing


【解决方案1】:

在请求外部打印时,您会得到空,因为请求是一个异步函数,并且只有在从网络接收到数据后才会填充数组。您需要将您的请求调用移动到一个函数中,并使用一个提供[Contact] 数组的完成块来调用它。这是一个例子:

func getContacts(completion: @escaping (Contact?) -> Void) {
    let jsonLocation = "http://raw.myjsondatalocation.com/contact.json"
    guard let url = URL(string: jsonLocation) else {
        completion(nil)
        return
    }

    URLSession.shared.dataTask(with: url) { (data,response,error) in
        guard let data = data else { return }
        do{
            let decoder = JSONDecoder()
            let contact = try decoder.decode(Contact.self, from:data)
            completion(contact)
        }
        catch let jsonErr{
            print("Error!",jsonErr)
            completion(nil)
        }
    }.resume()
}

然后这样称呼它:

getContacts { contact in
    print(contact?.contacts[0].name)
}

【讨论】:

    【解决方案2】:

    假设您正确解码了数据,您可以使用 map 来实现您想要的。确保您的 listOfNames 变量不以大写字母开头,因为它是一个变量。

    1. 声明一个类型为 [Contact] 的变量,其中包含名为 arrayOfContactNames 的名称数组:

      var arrayOfContactNames: [Contact] = []

    2. 一旦您的数据被解码,映射您的 listOfNames 并分配给 arrayOfContactNames,如果需要,调用 self.tableView.reloadData():

        let jsonLocation = "http://raw.myjsondatalocation.com/contact.json"
                guard let url = URL(string: jsonLocation) else {
                    return
                }
    
                URLSession.shared.dataTask(with: url){ (data,response,error) in
                    guard let data = data else { return }
                    do{
                        let decoder = JSONDecoder()
                        let listOfNames = try decoder.decode(Contact.self, from:data).contacts
                        // print(myListOfContacts)
                        print(listOfNames[0].name)
                        arrayOfContactNames = listOfNames.map { $0.name } 
                        // Once your data obtained, reload your tableview on the main thread to populate it
                        DispatchQueue.main.async {
                           self.tableView.reloadData()
                        }
                    }
                    catch let jsonErr{
                        print("Error!",jsonErr)
                    }
                    }.resume()
    

    【讨论】:

      【解决方案3】:

      https://app.quicktype.io/ 使用上面的这个网站,粘贴你的 json 响应...... 该网站将根据您的处理方式为您提供类或结构代码。

      这是结果

      // MARK: - Contacts
      class Contacts: Codable {
          let contacts: [Contact]
      
          init(contacts: [Contact]) {
              self.contacts = contacts
          }
      }
      
      // MARK: - Contact
      class Contact: Codable {
          let name: String
      
          init(name: String) {
              self.name = name
          }
      }
      

      使用它,您可以将数据存储到此类数组中。

      创建一个数组。

      var testArr = [Contacts]()
      

      在您发布的代码中

          let jsonLocation = "http://raw.myjsondatalocation.com/contact.json"
          guard let url = URL(string: jsonLocation) else {
              return
          }
      
          URLSession.shared.dataTask(with: url){ (data,response,error) in
              guard let data = data else { return }
              do{
                  let decoder = JSONDecoder()
                  let ListOfNames = try decoder.decode(Contact.self, from:data).contacts
                  // print(myListOfContacts)
                  print(ListOfNames[0].name)
              }
              catch let jsonErr{
                  print("Error!",jsonErr)
              }
              }.resume()
      

      您现在需要正确附加到类数组。在下面的代码块中查看更改。

      URLSession.shared.dataTask(with: url){ (data,response,error) in
                      guard let data = data else { return }
                  do{
                      let decoder = JSONDecoder()
                      let ListOfNames = try decoder.decode(Contact.self, from:data).contacts
                      // print(myListOfContacts)
                      for x in ListOfNames{
                          self.testArr.append(Contacts(contacts: x))
                      }
                      dump(self.testArr)
                  }
      

      编辑 --

      不确定这是否可行,但值得一试。

      URLSession.shared.dataTask(with: url){ (data,response,error) in
                      guard let data = data else { return }
                  do{
                      let decoder = JSONDecoder()
                      let jsonData = try JSONSerialization.jsonObject(with: data, options: []) as? [String: Any]
                      // print(myListOfContacts)
                      for x in jsonData{
                          self.testArr.append(x)
                      }
                      dump(self.testArr)
                  }
      

      我的想法是获取原始 json,循环遍历它并将原始数据附加到标准字符串数组。

      一旦您将数据存储在数组中,您就可以像往常一样对您的类数组进行追加。

      for x in self.testArr{
          self.classArray.append(Contacts(contacts: x))
      }
      

      【讨论】:

      • 您好,感谢您的建议。但是,我们必须使用他们给我们的 Codable。我尝试在 ListOfNames{print(x.name) self.testArr.append(String(x.name)) } 中使用 for x
      • 我们需要使用他们提供的 Codable 文件。我们不能使用我们自己的。我声明了一个var testArr = [String](),然后尝试添加: for x in ListOfNames{ print(x.name) self.testArr.append(String(x.name))} 但它仍然为我返回一个空数组。跨度>
      • @PtrickMahny 你能分享那个文件吗?我假设没有。对解决问题很有帮助。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-01-15
      • 2015-04-25
      • 1970-01-01
      • 2018-09-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多