OMDb API를 사용하여 Game of Thrones 에피소드 개요를 작성하려고합니다. 서버에서 정보를 얻고 있지만 UITableView에 데이터를 보내는 데 어려움을 겪고 있습니다. 나는 동일한 방법을 사용하여 SW의 API (스타 워즈)와 유사한 작업을 수행하고 그 다음 일Swift 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()
}
:
이 폐쇄하고 정의하는 하나를 호출 두 기능입니다.
모두 그러나 getTemporaryEpisode
얻은 에피소드의 시즌 번호를 인쇄해야 테스트를 위해 배치 인쇄 문 , 내가 찾을 대신에 (폐쇄 내에서) 제대로 첫 번째 인쇄 문 인쇄, 두 번째 동안 closure 외부의 오른쪽은 0 (값이 초기화되었는지 확인하기 위해 설정 한 기본값)을 인쇄합니다. 즉, episodeToAdd
에 더 이상 결과가 포함되지 않습니다.
예 : Winter Is Coming은 인클로저에서 1을 인쇄하지만 그 중 0은 인쇄합니다.
먼저 0을 인쇄하므로 스레드 문제이며 두 번째 print 문이 호출 될 때 완료되지 않은 것입니다. 나는 그것을 해결하는 방법을 모르겠습니다.
편집 : 나는 어리 석음으로 루프 내부의 주 스레드에 대한 호출을 배치했지만이 문제를 수정하지는 못했습니다.
죄송합니다, 이전에 본 적이 없습니다. 요약하자면, 여러분은'getTemporaryEpisode'에 대한 각 호출이'dispatchGroup.enter()'와 같은 것이어야하고, 완료 폐쇄 내에'dispatchGroup.leave()'가 있어야하고,'dispatchGroup .wait()'루프의 끝에서. 맞으면 인클로저에서 다시 보내는 목록에 추가 한 다음 루프가 완료되면 내 대리자에게 알리기 전에 배열을 정렬 할 수 있습니다. –
예, 당신은'DispatchGroup'을 가지고 올바른 생각을 가지고 있습니다. 핵심은'getTemporaryEpisode' 호출이 완료 핸들러를 호출하기 전에 루프가 완료된다는 것입니다. 모든 완료 핸들러가 반환 될 때까지 코드가 계속되는 것을 막기 위해서는'DispatchGroup.wait()'이 필요합니다. –