OMDb APIを使用してGame of Thronesエピソード概要を作成しようとしています。私は情報をサーバからうまく取得していますが、私はそのデータをUITableViewに送信するのが困難です。私は正確に同じ方法論を使用してSWのAPI(スターウォーズ)と同様の作業を行っているし、それがその後、働いスウィフト3エスケープクロージャーの変化が固まらない
func getAllForSeason(season: Int) {
let uri = "\(baseURL)\(urlId)&season=\(season)"
var episodeList = [EpisodeModel]()
let url = URL(string: uri)
let task = URLSession.shared.dataTask(with: url!) { (data, response, error) in
if error != nil {
print("Error retrieving information. No season found")
} else {
if let content = data {
do {
let seasonJSON = try JSONSerialization.jsonObject(with: content, options: .mutableContainers) as? [String: Any]
let episodesFound = seasonJSON?["Episodes"] as! [[String: String]]
for episodeJSON in episodesFound {
let number = Int(episodeJSON["Episode"] ?? "0") ?? 0
var episodeToAdd = EpisodeModel()
self.getTemporaryEpisode(season: season, number: number, completion: {(result:EpisodeModel) in
episodeToAdd = result
print(episodeToAdd.season)
})
print(episodeToAdd.season)
episodeList.append(episodeToAdd)
}
DispatchQueue.main.async {
self.delegate?.didGetSeason(episodes: episodeList)
}
} catch {
print ("Error retrieving information. No seasons found")
}
}
}
}
task.resume()
}
private func getTemporaryEpisode(season: Int, number: Int, completion: @escaping(_ response:EpisodeModel)->Void) {
let episode = EpisodeModel()
let uri = "\(baseURL)\(urlId)&season=\(season)&episode=\(number)"
let url = URL(string: uri)
let task = URLSession.shared.dataTask(with: url!) { (data, response, error) in
if error != nil {
print("Error downloading episode information. Empty Episode returned")
} else {
if let content = data {
do {
let episodeJSON = try JSONSerialization.jsonObject(with: content, options: JSONSerialization.ReadingOptions.mutableContainers) as? [String: Any]
episode.title = (episodeJSON?["Title"] as? String)?.description ?? ""
let dateString = (episodeJSON?["Released"] as? String)?.description ?? ""
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy MMM dd"
episode.releaseDate = dateFormatter.date(from: dateString) ?? Date()
episode.rating = (episodeJSON?["Rated"] as? String)?.description ?? ""
episode.season = Int(episodeJSON?["Season"] as? String ?? "") ?? 0
episode.number = Int(episodeJSON?["Episode"] as? String ?? "") ?? 0
let runtimeString = (episodeJSON?["Runtime"] as? String)?.description ?? "0 min"
let spaceIndex = runtimeString.index(of: " ") ?? runtimeString.endIndex
let minuteString = runtimeString[runtimeString.startIndex..<spaceIndex]
episode.minutes = Int(minuteString) ?? 0
episode.director = (episodeJSON?["Director"] as? String)?.description ?? ""
episode.writer = (episodeJSON?["Writer"] as? String)?.description ?? ""
let actorsString = (episodeJSON?["Actors"] as? String)?.description ?? ""
episode.actors = actorsString.components(separatedBy: ", ")
episode.plot = (episodeJSON?["Plot"] as? String)?.description ?? ""
} catch {
print("Error downloading episode information. Empty or incomplete episode returned")
}
}
}
completion(episode)
}
task.resume()
}
:
これは閉鎖し、それを定義するものを呼び出すの両方の関数です。
試験のために配置された印刷文は両方秒、しかし、私は最初のprint文プリントながら適切に(クロージャ内から)に代え見つけるgetTemporaryEpisode
を用いて得られたエピソードのシーズン番号を印刷する必要がありますクロージャーの外側の1つは0(値が初期化されていることを確認するために設定したデフォルト値)です。つまり、episodeToAdd
には結果が含まれません。
たとえば、Winter Is Comingはエンクロージャ内で1を出力しますが、そのうちの0が出力されます。
最初に0が出力されるので、スレッドの問題で、2番目のprint文が呼び出されるまでに完了していないと確信しています。私はそれを解決する方法だけではわかりません。
編集:私は愚かなループのメインスレッドへの私の呼び出しを置いたが、この問題を修正しなかった修正を実現しました。
申し訳ありませんが、それらを見たことがありません。しかし、大雑把に言えば、 'getTemporaryEpisode'の各呼び出しは、' dispatchGroup.enter() 'のようなものになり、' dispatchGroup.leave() 'が完了クロージャ内にあり、' dispatchGroupループの最後に.wait()を追加します。 これが正しい場合は、代わりにエンクロージャーに戻ってきたリストに追加して、ループが完了したら代理人に通知する前に配列を並べ替えることができます。 –
はい、あなたは 'DispatchGroup'で正しい考えを持っています。ポイントは、 'getTemporaryEpisode'呼び出しのどれかが完了ハンドラを呼び出す前にループが終了することです。 'DispatchGroup.wait()'が必要なのは、すべての補完ハンドラが返るまでコードが継続しないようにするためです。 –