使用 Alamofire 和 SwiftyJSON 正确解析具有多个对象的 JSON 数组

Posted

技术标签:

【中文标题】使用 Alamofire 和 SwiftyJSON 正确解析具有多个对象的 JSON 数组【英文标题】:Correctly parsing through a JSON array with multiple objects using Alamofire and SwiftyJSON 【发布时间】:2017-11-13 16:49:24 【问题描述】:

我可以打印出回复。但是我无法遍历数组并对其进行初始化。这就是我请求数据的方式:

Alamofire.request(url, method: .get, parameters: nil, encoding: URLEncoding.default).responseJSON  (response) in

    print(response.value!)

    guard let data = response.data else  return 
    let json = JSON(data: data)

    for r in json.arrayValue 
        let person = Person(json: r)
    

我添加了断点,但我无法理解为什么没有发生循环?

更新:

response.value! 示例:


  "pagination": 
    "object_count": 1,
    "page_number": 1
  ,
  "attendees": [
    
      "id": "818060297",
      "quantity": 1,
      "profile": 
        "first_name": "John",
        "last_name": "Doe",
        "company": "Apple",
        "name": "John Doe",
        "email": "john_doe@testmail.com",
        "job_title": "CEO"
      ,
      "status": "Attending"
    
  ]

更新 2

这是我的 AttendeesProfile 类:

class AttendeesProfile 

    var name: String?

    init(json: JSON) 
        self.name = json["name"].stringValue
    


现在我不确定如何让参加者类正常工作:

class Attendees 

    var attendees = [String]()
    var attendeesProfile: AttendeesProfile!

    init(json: JSON) 
        // Something here
    

【问题讨论】:

在不知道您在此处传递的数据是什么(或 JSON 的结构)的情况下,很难为您提供有助于解决问题的具体答案。 我将如何向您显示响应,因为它包含大量数据。 结构会有所帮助,那么它是包含许多孩子的***对象吗?这些孩子是否包含孩子等?你能在lldbpo json.arrayValue.count看看有没有条目吗? @AdamFallon 请查看更新后的答案 【参考方案1】:

我怀疑您的 guard 语句会在您循环遍历数组之前停止您的代码流:guard let data = response.data else return

通过这一行,您是说如果数据有某些东西,那么代码流可以继续。如果没有,请停止并返回。所以,你永远不会到达你的循环语句。

你确定你的response.data 有什么东西和nil 不同吗?你的print(response.value!) 有什么东西?

【讨论】:

当我在guard let 之后运行断点时,它会到达下一行。如果我打印 response.data 我得到▿ Optional<Data> ▿ some : 56757 bytes - count : 56757 ▿ pointer : 0x00007fed5f07e200 - pointerValue : 140657478328832 你可以尝试打印你的 json 常量吗? 我知道了expression produced error: error: Execution was interrupted, reason: EXC_BAD_ACCESS (code=1, address=0xfffffffffffffff8). The process has been returned to the state before expression evaluation. 哦,糟糕的错误!如果你打印你的常量数据?也许您的 JSON 初始化程序有问题,并且没有初始化您的 json 常量。所以,你的 json 常量是空的,你的循环没有理由循环。 当我在控制台打印出json后守卫让我得到整个json数组。它看起来好像在返回一个字典【参考方案2】:

您必须转换您的响应数据。你不能在未知的阵列上行走 我建议你使用 ObjectMapper 库。它可以将您的数据解析为您愿意的模型,如果收到的数据为零或不是您想要的模型,您可以轻松找到。不要忘记打印 response.data 以确保数据到底是什么。 https://github.com/Hearst-DD/ObjectMapper

【讨论】:

对不起,我没用过这个框架。仅使用 SwiftyJSON 就不可能实现它吗?如果不能,您能演示一下如何使用它来解决我的问题吗? 您确定您的回复不为空且方式正确吗? 是的,这正是我所展示的。 response.data = 56757 bytes 打印时告诉我 json 和 json.arrayValue 尝试字符串(数据:response.data!,编码:.utf8)【参考方案3】:

您可以实现几个符合Decodable 的结构,除其他外,这将使您的代码工作不依赖 SwiftyJSON。

从您提供的 JSON 数据出发,考虑以下三个简单结构:

struct AttendeeArray: Decodable 
   let attendees: [Attendee]


struct Attendee: Decodable 
   let status: String
   let profile: AttendeeProfile


struct AttendeeProfile: Decodable 
   let name: String
   let age: Int

每个结构都只包含您在 JSON 对象中定义的变量。

使用JSONDecoder,您现在可以像调用一样简单地解码您的 JSON 数据:

do  
   let array = try JSONDecoder().decode(AttendeeArray.self, from: data)
   // do whatever with your attendees array
 catch 
   // handle error if parsing fails
   print(error)

我创建了一个简单的 Playground,您可以通过添加以下代码以及上面的 Decodable 结构来测试它:

import Foundation

func decodeAttendees(json: String) -> AttendeeArray? 
   guard let data = json.data(using: .utf8) else  return nil 
   do 
       return try JSONDecoder().decode(AttendeeArray.self, from: data)
    catch 
       print("Error: \(error)")
       return nil
   


let json = """

   "attendees": [
       
           "status": "attending",
           "profile": 
               "name": "Joe",
               "age": 22
           
       ,
       
           "status": "not attending",
           "profile": 
               "name": "Bob",
               "age": 44
           
       
   ],
   "servlet": 
       "servlet-name": "cofaxCDS",
       "servlet-class": "org.cofax.cds.CDSServlet"
   

"""

let arr = decodeAttendees(json: json)
arr?.attendees[0].profile.name //"Joe"
arr?.attendees[1].status //"not attending"

现在,对于您当前的 Alamofire 完成处理程序,我猜想将其修改为以下内容一样简单:

Alamofire.request(url, method: .get, parameters: nil, encoding:   URLEncoding.default).responseJSON  (response) in
   guard let data = response.data else  return //remember to error if data is nil 
   do 
      let array = JSONDecoder().decode(AttendeesArray.self, from: data)
      //update your UI to show the array, or pass it on to a completion hanldler
    catch 
      //handle errors
   

【讨论】:

感谢您的详细解答。您是否建议使用 SwiftyJSON 在解析具有多个对象的 JSON 数组时存在限制?与此同时,我会尝试你的建议,看看我能做些什么。我只是觉得我已经在我的应用程序中使用不同的方法来解析 JSON 数据。或者这是正常的吗? SwiftyJSON 绝对是一个很棒的框架,它提供了很大的灵活性。我自己也用它。但是,我认为您至少应该知道替代方案。现在 Apple 添加了Codable 协议,处理原生对象的 JSON 编码/解码变得比以前容易得多。

以上是关于使用 Alamofire 和 SwiftyJSON 正确解析具有多个对象的 JSON 数组的主要内容,如果未能解决你的问题,请参考以下文章

SwiftyJson 和 Alamofire 使用的解码结构

如何使用 Alamofire 和 SwiftyJSON 正确解析 JSON

如何将 RxSwift 与 AlamoFire 和 SwiftyJSON 一起使用?

无法使用“((Any))”类型的参数列表调用“JSON” - 使用 AlamoFire 和 SwiftyJSON

使用 Alamofire 和 SwiftyJSON 时对 JSON 进行排序

使用 SwiftyJSON(和 Alamofire)解析 JSON 值