使用 NSJSONSerialization 从 json 响应构建对象

building objects from json response using NSJSONSerialization

使用 swift 1.2、xcode 6.3 和 IOS 8,我正在尝试使用 NSJSON 序列化从 json 响应构建对象 class。 json 响应是:

[{
  "_id" : "5470def9e0c0be27780121d7",
  "imageUrl" : "https:\/\/s3-eu-west-1.amazonaws.com\/myapi-static\/clubs\/5470def9e0c0be27780121d7_180.png",
  "name" : "Mondo",
  "hasVip" : false,
  "location" : {
    "city" : "Madrid"
  }
}, {
  "_id" : "540b2ff281b30f3504a1c72f",
  "imageUrl" : "https:\/\/s3-eu-west-1.amazonaws.com\/myapi-static\/clubs\/540b2ff281b30f3504a1c72f_180.png",
  "name" : "Teatro Kapital",
  "hasVip" : false,
  "location" : {
    "address" : "Atocha, 125",
    "city" : "Madrid"
  }
}, {
  "_id" : "540cd44581b30f3504a1c73b",
  "imageUrl" : "https:\/\/s3-eu-west-1.amazonaws.com\/myapi-static\/clubs\/540cd44581b30f3504a1c73b_180.png",
  "name" : "Charada",
  "hasVip" : false,
  "location" : {
    "address" : "La Bola, 13",
    "city" : "Madrid"
  }
}]

具有 NSJSONSerialization.JSONObjectWithData 实现的对象 class (Club.swift) 是:

class Club: NSObject {

    var id: String = ""
    var name: String = ""
    var imageUrl: String = ""
    var hasVip: Bool = false
    var desc: String = ""
    var location: [Location] = []

    init(JSONString: String) {

        super.init()

        var error : NSError?
        let JSONData = JSONString.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)

        let JSONDictionary: NSDictionary = NSJSONSerialization.JSONObjectWithData(JSONData!, options: nil, error: &error) as! NSDictionary

        self.setValuesForKeysWithDictionary(JSONDictionary as [NSObject : AnyObject])

    }

}

最后 ApiClient class 是

class ApiClient {
    func getList(completionHandler: ([JSON]) -> ()) {
        let URL = NSURL(string: "https://myapi.com/v1/clubs")
        let mutableURLRequest = NSMutableURLRequest(URL: URL!)

        mutableURLRequest.setValue("Content-Type", forHTTPHeaderField: "application/json")
        mutableURLRequest.HTTPMethod = "GET"
        mutableURLRequest.setValue("Bearer R01.iNsG3xjv/r1LDkhkGOANPv53xqUFDkPM0en5LIDxx875fBjdUZLn1jtUlKVJqVjsNwDe1Oqu2WuzjpaYbiWWhw==", forHTTPHeaderField: "Authorization")

        let manager = Alamofire.Manager.sharedInstance
        let request = manager.request(mutableURLRequest)

        request.responseJSON { (request, response, json , error) in
            if (json != nil){
                var jsonObj = JSON(json!)
                if let data = jsonObj["hits"].arrayValue as [JSON]?{

                    var aClub : Club = Club(JSONString: data)

                    println(aClub.name)

                    completionHandler(data)
                }
            }
        }
    }
}

但问题是当我尝试 println(aClub.name) 时,错误是

"cannot invoke initializer for type'Club' with an argument list of type (JSONString [JSON])"

我不知道,我怎么能使用 NSJSON序列化 class 和复杂的 JSON 响应。

jsonObj 似乎是一个 SwiftyJSON 对象,或者类似的东西,它用来代替 NSJSONSerialization,而不是与它结合使用。 data 变量是 JSON 对象的数组(即它是一个 [JSON]),而不是字符串。

但是您使用的是 Alamofire 的 responseJSON 方法,它会为您进行 JSON 解析。所以你不需要使用 NSJSONSerialization 或 SwiftyJSON。它已经将其解析为字典数组。

如果你想要一个 Club 个对象的数组,你可以迭代这个数组,从字典中构建 Club 个对象:

class ApiClient {
    func getList(completionHandler: ([Club]?, NSError?) -> ()) {
        let URL = NSURL(string: "https://myapi.com/v1/clubs")
        let mutableURLRequest = NSMutableURLRequest(URL: URL!)

        mutableURLRequest.setValue("Content-Type", forHTTPHeaderField: "application/json")
        mutableURLRequest.HTTPMethod = "GET"
        mutableURLRequest.setValue("Bearer R01.iNsG3xjv/r1LDkhkGOANPv53xqUFDkPM0en5LIDxx875fBjdUZLn1jtUlKVJqVjsNwDe1Oqu2WuzjpaYbiWWhw==", forHTTPHeaderField: "Authorization")

        let manager = Alamofire.Manager.sharedInstance
        let request = manager.request(mutableURLRequest)

        request.responseJSON { (request, response, json, error) in
            var clubs = [Club]()
            if let arrayOfDictionaries = json as? [[String: AnyObject]] {
                for dictionary in arrayOfDictionaries {
                    clubs.append(Club(dictionary: dictionary))
                }
                completionHandler(clubs, nil)
            } else {
                completionHandler(nil, error)
            }
        }
    }
}

您显然必须更改 Club 来处理字典对象:

class Club {

    var id: String!
    var name: String!
    var imageUrl: String!
    var hasVippler: Bool!
    var location: [String: String]!

    init(dictionary: [String: AnyObject]) {
        id         = dictionary["_id"] as? String
        name       = dictionary["name"] as? String
        imageUrl   = dictionary["imageUrl"] as? String
        hasVippler = dictionary["hasVip"] as? Bool
        location   = dictionary["location"] as? [String: String]
    }
}

最后,您的 table 视图控制器可以调用 API:

let apiClient = ApiClient()

var clubs: [Club]!

override func viewDidLoad() {
    super.viewDidLoad()

    apiClient.getList() { clubs, error in
        if clubs != nil {
            self.clubs = clubs
            self.tableView.reloadData()
        } else {
            println(error)
        }
    }
}