使用 Alamofire 和不记名令牌序列化对象
Posted
技术标签:
【中文标题】使用 Alamofire 和不记名令牌序列化对象【英文标题】:Serializing Objects with Alamofire and bearer token 【发布时间】:2015-04-19 21:13:18 【问题描述】:使用优秀的 Alamofire 库 v1.2,在 ios 8、Xcode 6.3 和 swift 项目中,我正在尝试从 JSON-API 响应序列化对象,我想知道实现它的最佳方法。 我认为下面代码中的主要问题是:
在类控制器中,println(data) 显示为零。 在俱乐部对象中 类、位置属性未正确映射。JSON-API 响应是:
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"
]
通用响应集合序列化:
@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)
)
俱乐部对象类
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
视图控制器类
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
println(clubs) 输出为:
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
【问题讨论】:
【参考方案1】:为了确定一下,您能否将 ViewController
类中的最后几行更改为以下内容?
request.responseJSON request, response, json, error in
println(request)
println(response)
println(json)
println(error)
我想确保您已正确设置您的请求并得到您期望的响应。这当然是成功的一半。一旦您可以验证这一点,我们就可以处理responseCollection
解析逻辑。
另外,您使用的是什么版本的 Xcode 以及什么版本的 Alamofire?
更新
您遇到的问题有两个方面。
问题 1
首先,您没有正确调用 responseCollection
方法。你应该这样称呼它:
request.responseCollection request, response, clubs: [Club], error in
println("request = \(request)")
println("response = \(response)")
println("clubs = \(clubs)")
println("error = \(error)")
这将正确调用您的Club
类。
问题 2
第二个问题是您没有在 Club
对象中实现 collection
方法。如果不实际遍历该系列,您将永远不会获得任何俱乐部。大致如下所示的内容应该可以让您朝着正确的方向前进。
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
一旦您的 collection
函数实际上迭代了 JSON 数组中的所有表示值,您应该有更多的运气。
奖励积分
对于奖励积分,这里有一些其他提示可以改进您的代码。
切换到在Club
类中使用可失败初始化程序,以确保仅在成功解析 JSON 时创建对象
在 responseCollection
完成闭包中更改您的实现,以实际存储新的俱乐部值并在您的表格视图中显示这些俱乐部。
返回到
responseCollection
闭包的对象不再是您可以与 SwiftyJSON 一起使用的 JSON AnyObject,而是一个俱乐部数组。
【讨论】:
我刚刚编辑了视图控制器类,添加了 println 输出并包含了输出。 Xcode的版本是6.3,Alamofire是1.2 我更新了我的答案以反映我认为您遇到的问题。代码可能不准确,因为我没有足够的示例代码来编译它,但这应该非常接近。 关于第二个问题,我已经按照你告诉我的那样在对象类中实现了这个函数,并且我已经添加了一个位置嵌套属性(我不知道它是否可以实现)。关于第一个问题,我更新了视图控制器类中的 request.responseCollection (..,..,[Club]?,..) 和 println(clubs) 输出,但不幸的是响应它是 nil 但如果我通过 request.responseJSON request, response, json, error in 更改请求,响应不是 nil 但我无法将 json("hits") 分配给俱乐部类跨度> 很抱歉@EdZ,但在这里为您提供帮助有点太难了。您在 Alamofire 中使用了非常先进的概念,但对 Alamofire 基础知识缺乏扎实的理解。我会首先尝试使用 SwiftyJSON 使用responseJSON
序列化方法来解析响应。一旦你让它正常工作并获得了一些使用 Alamofire 的经验,然后回到这种方法,希望事情会更有意义。我怎么强调都不过分,Alamofire 中的 README 非常棒,并且真的以非常简洁的方式将事情分解。以上是关于使用 Alamofire 和不记名令牌序列化对象的主要内容,如果未能解决你的问题,请参考以下文章
编写可通过 asp.net 身份用户和不记名令牌访问的单个 API
将带有完成处理程序的 Firebase IdToken 添加到每个 AlamoFire 请求