如何避免在JSON文件

时间:2018-01-05 02:06:36

标签: ios json swift

我有一个相当算法的问题。如json示例中所示,有几个具有相同名称的嵌套键(services)。当前parseData函数只是循环遍历services,它只会与第四个嵌套一样深。

我只对name数组中services键的值感兴趣,但也需要id来跟踪事物(例如,当在表中按下此id时,显示相应的标题) 。我知道这可以使用递归函数来解决,但我只是不知道如何启动,因为第一个for循环具有稍微不同的结构(例如,第一个嵌套没有id键)。最终name个键值将输入Tableview,例如如果Title 1属性为Title 2,则会显示idnil

我有两个问题: 1)这个相当不优雅的代码目前无法正常工作。我花了好几个小时试图修复它的错误,如果不是几天,但到目前为止没有成功。

serviceName按预期打印,但serviceMain.count打印为零,这意味着serviceMain为空?!我已将viewDidLoad(已注释掉的代码)中的代码放到didSet中,否则serviceMain没有及时更新并且tableView为空(名称列表,代码现在太长了,所以删除了tableView位),didSet最初做了伎俩,但我可能已经改变了一些东西,它不再起作用了。 我的代码有什么问题?

2)你能否建议一个解决方案如何使用递归函数等使这段代码更优雅和有效?相同的JSON结构可以更深入(服务数组存在10倍等),我只提供了以下JSON作为示例。非常感谢您阅读,希望您能够提供帮助!

JSON数据(简化为path = "http://example.com/services"

{
  “Provider1”: {
    "name": “Provider1”,
    "services": [
      {
        "id": “901”,
        "name": “Title 1”,
        "services": [
          {
            "id": “950”,
            "name": “Title 1A”,
            "services": []
          },
          {
            "id": “951”,
            "name": “Title 1B”,
            "services": []
          }
        ]
      },
      {
        "id": "970”,
        "name": “Title 2”,
        "services": [
          {
            "id": “971”,
            "name": “Title 2A”,
            "services": [          {
                "id": “972”,
                "name": “Subtitle 21A”,
                "services": []
              },
              {
                "id": “973”,
                "name": “Subtitle 21B”,
                "services": []
          }]
          },
          {
            "id": “974”,
            "name": “Title 2B”,
            "services": []
          }
        ]},
  “Provider2”: {...
    ...

}

Service.swift:

import UIKit

struct Service {
    var id: Int?
    var name: String?

    enum SerializationError: Error {
        case missing(String)
        case invalid(String, Any)
    }

    init(json: [String: Any]) throws {
        guard let id = (json["id"] as? NSString)?.integerValue else { throw SerializationError.missing("id is missing")}
        guard let name = json["name"] as? String else { throw SerializationError.missing("name is missing")}
    }

    static let path = "http://example.com/services"

    static func parseData(providerName: String, id: Int? = nil, completion: @escaping ([Service]) -> ()) {

        var request = URLRequest(url: URL(string: path)!)
        request.httpMethod = "GET"

        let task = URLSession.shared.dataTask(with: request) { (data:Data?, response:URLResponse?, error:Error?) in

            var services: [Service] = []
            if let data = data {
                do {
                    let json = try JSONSerialization.jsonObject(with: data, options: .mutableContainers)

                    // A. Main Array
                    guard let jsonArray = json as? [String: Any],
                        let providerMain = jsonArray[providerName] as? [String: Any],
                        let servicesMain = providerMain["services"] as? [Any] else {
                            return
                    }

                    // B. First nest
                    for service1 in servicesMain {
                        guard let service11 = service1 as? [String: Any],
                            let service12 = service11["services"] as? [Any],
                            let service11Id = (service11["id"] as? NSString)?.integerValue else {
                                return
                        }
                        if let subServices = try? Service(json: service11), id == nil {
                            services.append(subServices)
                        }

                    // C. Second nest
                        for service2 in service12 {
                            guard let service21 = service2 as? [String:Any],
                                let service22 = service21["services"] as? [Any],
                                let service21Id = (service21["id"] as? NSString)?.integerValue else {
                                    return
                            }

                            if let subServices = try? Service(json: service21), service11Id == id {
                                services.append(subServices)
                            }

                    // D. Third nest
                            for service3 in service22 {
                                guard let service31 = service3 as? [String:Any],
                                    let service32 = service31["services"] as? [Any],
                                    let service31Id = (service31["id"] as? NSString)?.integerValue else {
                                        return
                                }

                                if let subServices = try? Service(json: service31), service21Id == id {
                                    services.append(subServices)
                                }
                    // E. Fourth nest
                                for service4 in service32 {
                                    guard let service41 = service4 as? [String:Any] else {
                                        return
                                    }

                                    if let subServices = try? Service(json: service41), service31Id == id {
                                        services.append(subServices)
                                    }

                                }
                            }
                        }
                    }
                } catch {
                    print(error.localizedDescription)
                }
                completion(services)
            }
        }
        task.resume()
    }
}

ViewController.swift:

import UIKit

class ViewController: UIViewController {
    var serviceMain: [String] = [] {
        didSet{
            Service.parseData(providerName: "Provider1", id: nil) { (services: [Service]) in
                for service in services {
                    guard let serviceName = service.name else { return }
                    self.serviceMain.append(serviceName)
                    print(serviceName)
                }
            }
        }
    }


    override func viewDidLoad() {
        super.viewDidLoad()
// Below commented out code also produced zero count in serviceMain        
// Service.parseData(providerName: "Provider1", id: nil) { (services: [Service]) in
//            for service in services {
//                guard let serviceName = service.name else { return }
//                self.serviceMain.append(serviceName)
//                print(serviceName)
//            }
//        }
        print("serviceMain count: \(serviceMain.count)")
    }


}

1 个答案:

答案 0 :(得分:0)

对于JSON解析器,您可以使用ObjectMapper

在您的情况下,例如,

class ProviderWrapper: Mappable{
    var provider1: Provider?
    var provider2: Provider?
    .....
}

class Provider: Mappable{
    var name: String?
    var services: [Service]?
}

class Service: Mappable{

   var id: Int?
   var name: String?
   var services: [Service]?
}