简体   繁体   中英

Serializing Objects with Alamofire and bearer token

Using the excellent Alamofire library v1.2, in a IOS 8, Xcode 6.3 and swift project, I'm trying to serialize objects from JSON-API response and I would like to know which is the best way to accomplish it. I think the main issues in the code below are:

  • in the class controller, println(data) shows nil.
  • in the Club Object Class, location property is not mapped correctly.

The JSON-API response is:

hits = [{
  "_id" : "5470def9e0c0be27780121d7",
  "imageUrl" : "https:\/\/s3-eu-west-1.amazonaws.com\/api-static\/clubs\/5470def9e0c0be27780121d7_180.png",
  "name" : "Mondo",
  "hasVip" : false,
  "location" : {
    "city" : "Madrid"
  }
}, {
  "_id" : "540b2ff281b30f3504a1c72f",
  "imageUrl" : "https:\/\/s3-eu-west-1.amazonaws.com\/api-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\/api-static\/clubs\/540cd44581b30f3504a1c73b_180.png",
  "name" : "Charada",
  "hasVip" : false,
  "location" : {
    "address" : "La Bola, 13",
    "city" : "Madrid"
  }
}]

Generic Response Collection Serialization:

@objc public protocol ResponseCollectionSerializable {
    static func collection(#response: NSHTTPURLResponse, representation: AnyObject) -> [Self]
}

extension Alamofire.Request {
    public func responseCollection<T: ResponseCollectionSerializable>(completionHandler: (NSURLRequest, NSHTTPURLResponse?, [T]?, NSError?) -> Void) -> Self {
        let serializer: Serializer = { (request, response, data) in
            let JSONSerializer = Request.JSONResponseSerializer(options: .AllowFragments)
            let (JSON: AnyObject?, serializationError) = JSONSerializer(request, response, data)
            if response != nil && JSON != nil {
                return (T.collection(response: response!, representation: JSON!), nil)
            } else {
                return (nil, serializationError)
            }
        }

        return response(serializer: serializer, completionHandler: { (request, response, object, error) in
            completionHandler(request, response, object as? [T], error)
        })
    }
}

the Club Object Class

final class Club: ResponseCollectionSerializable {

    @objc static func collection(#response: NSHTTPURLResponse, representation: AnyObject) -> [Club] {
        var clubs = [Club]()

        if let representation = representation as? [[String: AnyObject]] {
            for representationValue in representation {
                let club = Club(JSON: representationValue)
                clubs.append(club)
            }
        }

        return clubs
    }

    let id: String
    let name: String
    let imageUrl: String
    let hasVip: Bool
    let location: String

    init(JSON: AnyObject) {
        id = JSON.valueForKeyPath("id") as! String
        name = JSON.valueForKeyPath("name") as! String
        imageUrl = JSON.valueForKeyPath("imageUrl") as! String
        hasVip = JSON.valueForKeyPath("hasVip") as! Bool

        //is OK this implementation?
        location = JSON.valueForKeyPath("location") as! String
    }
}

the View Controller Class

class ClubsViewController: UIViewController, UITableViewDataSource{

    var results: [JSON]? = []
    var clubs: [Club]?

    @IBOutlet var tableview:UITableView!



    override func viewDidLoad() {
        super.viewDidLoad()
        self.loadClubsObjects()
    }

    func loadClubsObjects(){


        var URL = NSURL(string: "https://api.com/v1/clubs")
        var mutableURLRequest = NSMutableURLRequest(URL: URL!)
        mutableURLRequest.setValue("Content-Type", forHTTPHeaderField: "application/x-www-form-urlencoded")
        mutableURLRequest.HTTPMethod = "GET"
        mutableURLRequest.setValue("Bearer R01.iNsG3xjv/r1LDkhkGOANPv53xqUFDkPM0en5LIDxx875fBjdUZLn1jtUlKVJqVjsNwDe1Oqu2WuzjpaYbiWWhw==", forHTTPHeaderField: "Authorization")
        let manager = Alamofire.Manager.sharedInstance
        let request = manager.request(mutableURLRequest)
        request.responseCollection { (request, response, clubs: [Club]?, error) in

        println("request = \(request)")
        println("response = \(response)")
        println("clubs = \(clubs)")
        println("error = \(error)")

            if (json != nil){
                var jsonObj = JSON(json!)
                if let data = jsonObj["hits"].arrayValue as [JSON]? {
                    self.results = data
                    self.tableview.reloadData()

                }
            }
        }



    }

    func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return self.results?.count ?? 0
    }

    func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
        var cell = tableView.dequeueReusableCellWithIdentifier("clubsObjectCell") as! ClubsTableViewCell
        cell.clubsObject = self.results?[indexPath.row]
        return cell    }

}

the println(clubs) output is:

   request = <NSMutableURLRequest: 0x7fd553725870> { URL: https://api.com/v1/clubs }
response = Optional(<NSHTTPURLResponse: 0x7fd553439e20> { URL: https://api.com/v1/clubs } { status code: 200, headers {
    "Access-Control-Allow-Headers" = "X-Requested-With, Accept, Origin, Referer, User-Agent, Content-Type, Authorization";
    "Access-Control-Allow-Methods" = "GET,PUT,POST,DELETE,OPTIONS";
    "Access-Control-Allow-Origin" = "*";
    Connection = "keep-alive";
    "Content-Encoding" = gzip;
    "Content-Type" = "application/json; charset=utf-8";
    Date = "Tue, 21 Apr 2015 20:18:07 GMT";
    Etag = "W/\"sEDn5KBhpfpInjAtNsF4gQ==\"";
    Server = "nginx/1.6.2";
    "Transfer-Encoding" = Identity;
    Vary = "Accept-Encoding";
    "X-Powered-By" = Express;
} })
clubs = Optional([])
error = nil

Just to make sure, could you change your last lines in the ViewController class to be the following?

request.responseJSON { request, response, json, error in
    println(request)
    println(response)
    println(json)
    println(error)
}

I want to make sure that you have set up your request properly and are getting the response back that you expect. That is certainly half the battle. Once you can verify that, then we can work on the responseCollection parsing logic.

Also, what version of Xcode are you using and what version of Alamofire?


UPDATE

The issue you are having is two-fold.

Issue 1

First, you are not calling your responseCollection method correctly. You should instead call it as follows:

request.responseCollection { request, response, clubs: [Club], error in
    println("request = \(request)")
    println("response = \(response)")
    println("clubs = \(clubs)")
    println("error = \(error)")
}

This will then call into your Club class properly.

Issue 2

The second issue is that you are not implementing the collection method inside your Club object. You're never going to get any clubs without actually iterating through the collection. Something roughly like the following should get you going in the right direction.

final class Club: ResponseCollectionSerializable {
    @objc static func collection(#response: NSHTTPURLResponse, representation: AnyObject) -> [Club] {
        var clubs = [Club]()

        if let representation = representation as? [[String: AnyObject]] {
            for representationValue in representation {
                let club = Club(JSON: representationValue)
                clubs.append(club)
            }
        }

        return clubs
    }

    let id: String
    let name: String
    let imageUrl: String
    let hasVip: Bool

    init(JSON: AnyObject) {
        id = JSON.valueForKeyPath("id") as! String
        name = JSON.valueForKeyPath("name") as! String
        imageUrl = JSON.valueForKeyPath("imageUrl") as! String
        hasVip = JSON.valueForKeyPath("hasVip") as! Bool
    }
}

Once your collection function is actually iterating through all the representation values in the JSON array, you should have more luck.

Bonus Points

For bonus points, here are a few other tips to improve your code.

  • Switch to using a failable initializer in your Club class to guarantee that objects are only created if the JSON is parsed successfully
  • Change your implementation inside the responseCollection completion closure to actually store the new clubs value and display those clubs in your table view.

The object returned to the responseCollection closure is no longer a JSON AnyObject that you can use with SwiftyJSON, but instead an array of Clubs.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM