/// ContentLoader is a lightweight state manager for loading and displaying content and/or errors. /// It allows you to repeatedly make requests and display new content or cached content in the event of an error. /// Commonly known as RemoteData or LCE (Loading / Content / Error). /// Inspired by https://tech.instacart.com/lce-modeling-data-loading-in-rxjava-b798ac98d80 /// final class ContentLoader { init() { } @discardableResult func loader(_ loader: (() -> Void)?) -> ContentLoader { self.loader = loader return self } @discardableResult func update(_ update: (() -> Void)?) -> ContentLoader { self.update = update return self } private var loader: (() -> Void)? private var update: (() -> Void)? var loading: Bool = false var content: T? var error: Error? var hasContent: Bool { return content != nil } var hasError: Bool { return error != nil } func load() { loading = true loader?() } func success(content: T) { self.content = content self.loading = false update?() } func failure(error: Error?) { self.error = error self.loading = false update?() } } // usage psudocode class ViewController { let contentLoader = ContentLoader() init { self.contentLoader.loader({ async { loadData { data, error in if let json = JSON(data) { self.contentLoader.success(json) } else { self.contentLoader.failure(error ?? ParsingError()) } } } }).update({ updateTheUI() }).load() } func updateTheUI() { // Handle the state enum to draw correct UI } }