Open Taehyeon-Kim opened 10 months ago
import Foundation import Combine struct Article: Decodable { let title: String let description: String let author: String } /// Duplicate, concurrent network calls class ArticleLoader { typealias Publisher = AnyPublisher<Article, Error> private let queue = DispatchQueue(label: "ArticleLoader") private let urlSession: URLSession private let decoder: JSONDecoder private var publishers = [URL: Publisher]() init(urlSession: URLSession = .shared, decoder: JSONDecoder = .init()) { self.urlSession = urlSession self.decoder = decoder } /// 해당 메서드가 동일한 URL로 병렬 또는 빠르게 연속으로 여러번 호출된다고 가정 /// 메서드를 호출할때마다 새로운 퍼블리셔 생성, 이 경우 네트워크 요청 중복 발생 func loadArticles(from url: URL) -> AnyPublisher<Article, Error> { if let publisher = publishers[url] { return publisher } let publisher = urlSession .dataTaskPublisher(for: url) .map(\.data) .decode(type: Article.self, decoder: decoder) .receive(on: queue) /// 이전 publisher가 메모리에 남아있지 않도록 함, 완료되면 dictionary에서 publisher를 제거 .handleEvents(receiveCompletion: { [weak self] _ in self?.publishers[url] = nil }) .share() .eraseToAnyPublisher() publishers[url] = publisher return publisher } }
Links: