2017-08-08 215 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

很高興我可以幫助:) –