Google 书籍 API 解析
Google Books API parsing
所以我正在尝试解析 Google 书籍 API 响应。我想获得标题、描述、thumbnailUrl、作者和发布的数据。这是问题所在:
func getBooksFrom(completion: @escaping (Result<[[String: AnyObject]]>) -> Void) {
URLSession.shared.dataTask(with: url) { (data, response, error) in
guard error == nil else { return completion(.Error(error!.localizedDescription)) }
guard let data = data else { return
completion(.Error(error!.localizedDescription)) }
do {
if let json = try JSONSerialization.jsonObject(with: data, options: [.mutableContainers]) as? [String: AnyObject] {
if let items = json["items"] as? [[String: AnyObject]] {
DispatchQueue.main.async {
completion(.Succes(items))
}
}
}
} catch let error {
print(error.localizedDescription)
return completion(.Error(error.localizedDescription))
}
}.resume()
}
在 ViewDidLoad 的视图控制器上我有
let service = ApiService()
service.getBooksFrom { (result) in
switch result {
case .Succes(let data):
self.parseData(array: data)
case .Error(let message):
self.showAlertWith(title: "Error", and: message)
}
}
所以这是非常简单的解析,但是...
当我想将项目映射到 Book Object 时,我必须:
func parseData(_ data: [[String: AnyObject]]) -> [Book]{
for item in data {
if let volumeInfo = item["volumeInfo"] as? [String: AnyObject] {
let books = data.map { (jsonDictionary) -> Book in
let title = volumeInfo["title"] as? String ?? ""
let publishedData = volumeInfo["publishedDate"] as? String ?? ""
let authors = volumeInfo["authors"] as? [String] ?? [""]
let description = volumeInfo["description"] as? String ?? ""
let newBook = Book(title: title, publishedData: publishedData, description: description)
return newBook
}
return books
}
}
return [Book]()
}
这是一种非常糟糕的方法。你必须 return 在底部预订,因为 for-loop,并且
VolumeInfo 是下一个字典,所以我真的不知道如何映射它并获取例如作者,因为它是下一个数组..
一个样本JSON object:
{
"items":[
{
"volumeInfo":{
"title":"The Ancestor's Tale",
"subtitle":"A Pilgrimage to the Dawn of Life",
"authors":[
"Richard Dawkins",
"Yan Wong"
]
"publishedDate":"2016-04-28",
"description":"A fully updated ",
"imageLinks":{
"smallThumbnail":"http://books.google.com/books/content?id=vzbVCQAAQBAJ&printsec=frontcover&img=1&zoom=5&edge=curl&source=gbs_api",
"thumbnail":"http://books.google.com/books/content?id=vzbVCQAAQBAJ&printsec=frontcover&img=1&zoom=1&edge=curl&source=gbs_api"
}
}
]}
所以当你有字符串数组时这很简单:值,但是当你有字典 VolumeInfo 中的字典或像作者这样的字符串数组时,你应该如何以正确的方式映射?
我个人觉得用 URLSession 解析 swift 中的对象的方法比较笨拙。每当我可以使用 Alamofire in combination with the AlamofireObjectMapper.
这允许您创建一个简单的对象。例如:
class Book: Mappable {
var title: String?
var subtitle: String?
var description: String?
required init?(map: Map){
}
func mapping(map: Map) {
title <- map["title"]
subtitle <- map["subtitle"]
description <- map["description"]
}
}
当您发出请求时,您可以使用 responseObject 方法直接解析您的对象并分配适当的类型。
Alamofire.request(URL).responseObject { (response: DataResponse<Book>) in
let book = response.result.value
print(book?.title)
}
对于这个例子,我只是简单地解析了一本书。但是这个概念也可以很容易地扩展到数组或嵌套的 json 对象。我个人认为这比直接使用 URLSession 产生的代码更简洁。
所以我正在尝试解析 Google 书籍 API 响应。我想获得标题、描述、thumbnailUrl、作者和发布的数据。这是问题所在:
func getBooksFrom(completion: @escaping (Result<[[String: AnyObject]]>) -> Void) {
URLSession.shared.dataTask(with: url) { (data, response, error) in
guard error == nil else { return completion(.Error(error!.localizedDescription)) }
guard let data = data else { return
completion(.Error(error!.localizedDescription)) }
do {
if let json = try JSONSerialization.jsonObject(with: data, options: [.mutableContainers]) as? [String: AnyObject] {
if let items = json["items"] as? [[String: AnyObject]] {
DispatchQueue.main.async {
completion(.Succes(items))
}
}
}
} catch let error {
print(error.localizedDescription)
return completion(.Error(error.localizedDescription))
}
}.resume()
}
在 ViewDidLoad 的视图控制器上我有
let service = ApiService()
service.getBooksFrom { (result) in
switch result {
case .Succes(let data):
self.parseData(array: data)
case .Error(let message):
self.showAlertWith(title: "Error", and: message)
}
}
所以这是非常简单的解析,但是... 当我想将项目映射到 Book Object 时,我必须:
func parseData(_ data: [[String: AnyObject]]) -> [Book]{
for item in data {
if let volumeInfo = item["volumeInfo"] as? [String: AnyObject] {
let books = data.map { (jsonDictionary) -> Book in
let title = volumeInfo["title"] as? String ?? ""
let publishedData = volumeInfo["publishedDate"] as? String ?? ""
let authors = volumeInfo["authors"] as? [String] ?? [""]
let description = volumeInfo["description"] as? String ?? ""
let newBook = Book(title: title, publishedData: publishedData, description: description)
return newBook
}
return books
}
}
return [Book]()
}
这是一种非常糟糕的方法。你必须 return 在底部预订,因为 for-loop,并且 VolumeInfo 是下一个字典,所以我真的不知道如何映射它并获取例如作者,因为它是下一个数组..
一个样本JSON object:
{
"items":[
{
"volumeInfo":{
"title":"The Ancestor's Tale",
"subtitle":"A Pilgrimage to the Dawn of Life",
"authors":[
"Richard Dawkins",
"Yan Wong"
]
"publishedDate":"2016-04-28",
"description":"A fully updated ",
"imageLinks":{
"smallThumbnail":"http://books.google.com/books/content?id=vzbVCQAAQBAJ&printsec=frontcover&img=1&zoom=5&edge=curl&source=gbs_api",
"thumbnail":"http://books.google.com/books/content?id=vzbVCQAAQBAJ&printsec=frontcover&img=1&zoom=1&edge=curl&source=gbs_api"
}
}
]}
所以当你有字符串数组时这很简单:值,但是当你有字典 VolumeInfo 中的字典或像作者这样的字符串数组时,你应该如何以正确的方式映射?
我个人觉得用 URLSession 解析 swift 中的对象的方法比较笨拙。每当我可以使用 Alamofire in combination with the AlamofireObjectMapper.
这允许您创建一个简单的对象。例如:
class Book: Mappable {
var title: String?
var subtitle: String?
var description: String?
required init?(map: Map){
}
func mapping(map: Map) {
title <- map["title"]
subtitle <- map["subtitle"]
description <- map["description"]
}
}
当您发出请求时,您可以使用 responseObject 方法直接解析您的对象并分配适当的类型。
Alamofire.request(URL).responseObject { (response: DataResponse<Book>) in
let book = response.result.value
print(book?.title)
}
对于这个例子,我只是简单地解析了一本书。但是这个概念也可以很容易地扩展到数组或嵌套的 json 对象。我个人认为这比直接使用 URLSession 产生的代码更简洁。