2017-08-08 214 views
0

所以我试图解析Google Books API的回应。我想获得标题,说明,thumbnailUrl,作者和发布的数据。这里的问题是:谷歌图书API解析

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对象我必须:

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]() 
} 

这是超级可怕的方式来做到这一点。你必须在底部归还书,因为for循环,并 VolumeInfo旁边迪科tionary,所以我真的不知道究竟如何映射,并得到例如作者,因为这是下一个数组..

一个样品JSON对象:

{ 
    "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中的字典或作为字符串的数组时?

+0

'authors'是一个String数组,而不是一个字典。 – Larme

+0

@Larme是的,你是对的:) – Magnifique

+0

编辑你的问题与JSON示例,而不是在评论中的链接,这可能是有用的...请注意,'volumeInfo [“description”] as?字符串?? “”所有论文“?”测试可以在Book的'init'方法中完成,并且在这里做一个更清晰的解析。 – Larme

回答

1

我个人发现用URLSession在swift中解析对象的方式相对笨拙。无论何时我可以使用Alamofire结合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直接导致更清洁的代码。

+0

非常感谢,它的工作! <3在这个典型的JSON响应中,您必须使用reponseArray和kayPath,但一切都很完美,而且更容易! :) – Magnifique

+0

很高兴我可以帮助:) –