유저가 새로운 뉴스 피드를 보고 싶다고 요청한 상황을 가정해봅시다. (새로고침 등)
메인스레드에서 user event gesture를 핸들링합니다. 여기에서 데이터베이스 작업을 처리하는 직렬큐(SerialQueue)에 요청을 비동기식(async)으로 dispatch합니다.
그 이유는 두 가지입니다.
네트워킹 요청의 결과가 들어오면 동시 대기열(concurrent queue)인 delegate queue에서 URLSession 콜백이 호출됩니다. 각 결과에 대한 완료 핸들러에서 각 피드의 최신 요청으로 데이터베이스를 동기식으로 업데이트하여 나중에 사용할 수 있도록 캐시합니다.
그리고 최종적으로 UI를 업데이트 하기 위해 main thread를 깨울 것 입니다.
func deserializeArticles(from data: Data) throws -> [Article] { /* ... */ }
func updateDatabase(with articles: [Article], for feed: Feed) { /* ... */ }
let urlSession = URLSession(configuration: .default, delegate: self, delegateQueue: concurrentQueue)
for feed in feedsToUpdate {
let dataTask = urlSession.dataTask(with: feed.url) { data, response, error in
// ...
guard let data = data else { return }
do {
let articles = try deserializeArticles(from: data)
databaseQueue.sync {
updateDatabase(with: articles, for: feed)
}
} catch { /* ... */ }
}
dataTask.resume()
}
위의 과정을 코드로 나타낸 것 입니다.
이렇게 straight-line 코드를 작성했지만 이 코드에는 몇 가지 숨겨진 성능 이슈가 있습니다.