Created
June 17, 2020 18:25
-
-
Save angelinaFri/021ff8a24d91c2f16dd77688feec568f to your computer and use it in GitHub Desktop.
Populating UI from Multiple Services
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
struct Article {} | |
struct Picture {} | |
typealias ArticleLoaderResult = Swift.Result<[Article], Error> | |
protocol ArticleLoader { | |
func load(date: Date, completion: @escaping (ArticleLoaderResult) -> Void) | |
} | |
typealias PictureLoaderResult = Swift.Result<[Picture], Error> | |
protocol PictureLoader { | |
func load(date: Date, completion: @escaping (PictureLoaderResult) -> Void) | |
} | |
typealias DailyLoaderResult = Swift.Result<String, Error> | |
protocol DailyLoader { | |
func load(completion: @escaping (DailyLoaderResult) -> Void) | |
} | |
struct MainModel { | |
let articles: [Article] | |
let pictures: [Picture] | |
let dailyQuote: String | |
} | |
protocol MainLoader { | |
typealias Result = Swift.Result<MainModel, Error> | |
func load(date: Date, completion: @escaping (Result) -> Void) | |
} | |
class MainLoaderAdapter: MainLoader { | |
let articleLoader: ArticleLoader | |
let pictureLoader: PictureLoader | |
let dailyLoader: DailyLoader | |
private let queue = DispatchQueue(label: "MainLoaderAdapter.queue") | |
init(articleLoader: ArticleLoader, pictureLoader: PictureLoader, dailyLoader: DailyLoader) { | |
self.articleLoader = articleLoader | |
self.pictureLoader = pictureLoader | |
self.dailyLoader = dailyLoader | |
} | |
private struct PartialResult { | |
var articles: [Article]? { | |
didSet { checkCompletion() } | |
} | |
var pictures: [Picture]? { | |
didSet { checkCompletion() } | |
} | |
var dailyQoute: String? { | |
didSet { checkCompletion() } | |
} | |
var error: Error? { | |
didSet { checkCompletion() } | |
} | |
var completion: ((MainLoader.Result) -> Void)? | |
private mutating func checkCompletion() { | |
if let error = error { | |
completion?(.failure(error)) | |
} else if let articles = articles, let pictures = pictures, let dailyQuote = dailyQoute { | |
completion?(.success(MainModel( | |
articles: articles, | |
pictures: pictures, | |
dailyQuote: dailyQuote))) | |
completion = nil | |
} | |
} | |
} | |
func load(date: Date, completion: @escaping (MainLoader.Result) -> Void) { | |
var partialResult = PartialResult(completion: completion) | |
articleLoader.load(date: date) { articleResult in | |
self.queue.sync { | |
switch articleResult { | |
case let .failure(error): | |
partialResult.error = error | |
case let .success(value): | |
partialResult.articles = value | |
} | |
} | |
} | |
pictureLoader.load(date: date) { pictureResult in | |
self.queue.sync { | |
switch pictureResult { | |
case let .failure(error): | |
partialResult.error = error | |
case let .success(value): | |
partialResult.pictures = value | |
} | |
} | |
} | |
dailyLoader.load { dailyResult in | |
self.queue.sync { | |
switch dailyResult { | |
case let .failure(error): | |
partialResult.error = error | |
case let .success(value): | |
partialResult.dailyQoute = value | |
} | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment