- ✍️ Description
- 🖥 Example
- 🎟 Demo
- 🔨 Customization
- 💻 How to use
⚠️ Requirements- 💆 Inspiration
- 💪 Contribute
The AsyncViewController
works as a bridge between loading your data for a specific view and presenting the view controller. It presents a loading screen as long as you're waiting for a response and you can provide the destination view controllers (either for success or error) beforehand without having to put all this logic into your final view controller.
The old way:
The initial motivation was to get rid of the optional object property inside of a detail view controller and also remove the logic from the detail view controller including the data loading and displaying a loading view.
Imagine a BookViewController:
class BookViewController: UIViewController {
var book: Book?
// Having the represented object for this view controller as an optional is inconvenient.
var loadingView: LoadingView?
// Also having the loading view in here is inconvenient since we only need it once in the beginning.
init(bookId: Int) {
super.init(...)
// Load the book here
MyLibrary.loadBook(id: bookId) { result in
// Refresh UI
}
}
override func viewDidLoad() {
super.viewDidLoad()
// Then you initialize your UI, first without data but after loading again with data.
}
}
The new way:
The AsyncViewController
burries the boiler plate code and provides you a handy initializer to define your asynchronous call, the view controller when it was successful, and a resolution action when it fails.
Imagine calling this from a BookShelfViewController:
func presentBookViewController(bookId: Int) {
let asyncViewController = AsyncViewController(load: { callback in
MyLibrary.loadBook(id: bookId, handler: callback)
}, success: { book -> BookViewController in
return BookViewController(book: book)
}) { error -> AsyncViewController<BookViewController, String, Error>.FailureResolution in
return .showViewController(ErrorViewController(error))
}
asyncViewController.overridesNavigationItem = true
present(asyncViewController, animated: true)
}
You can find this demo app in this repository.
Error Handling:
You can provide a custom action when the loading fails. The FailureResolution
enum provides a case that you can use to pass a callback.
Maybe you want to dismiss the view controller, or pop it from the navigation stack.
return .custom({ asyncViewController in
asyncViewController.dismiss(animated: true)
})
Custom Loading View:
If you want to show your own loading view you can use any UIViewController
conforming to the LoadingAnimatable
protocol described here.
asyncViewController.loadingViewController = MyLoadingViewController()
Check out the Demo
Swift Package Manager:
Add the following to your Package.swift
file:
dependencies: [
.package(url: "https://github.com/lukaswuerzburger/AsyncViewKit.git", from: "3.0.0")
]
- Swift 5+
- iOS 9+
- Xcode 9+
- Swift Talk: Loading View Controllers
- Swift & Fika 2018 – John Sundell: The Lost Art of System Design
Issues and pull requests are welcome.