Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
View Controller Containment Injecting Empty Views
//: Playground - noun: a place where people can play
import UIKit
import PlaygroundSupport
typealias JSONDictionary = [String:Any]
struct Resource<T> {
let url :URL
var parse :(Data) -> T?
}
struct Pokemon {
var name :String
}
extension Pokemon {
init?(dictionary :JSONDictionary) {
guard let name = dictionary["name"] as? String else {
fatalError("name not found")
}
self.name = name
}
}
class WebService {
func load<T>(resource :Resource<T>, completion:@escaping (T?) -> ()) {
URLSession.shared.dataTask(with: resource.url) { (data, _, _) in
DispatchQueue.main.async {
completion(resource.parse(data!))
}
}.resume()
}
}
let pokemonURL = URL(string: "https://still-wave-26435.herokuapp.com/pokemon/all")!
let pokemonResource = Resource<[Pokemon]>(url: pokemonURL) { result in
let json = try! JSONSerialization.jsonObject(with: result, options: [])
let dictionaries = json as! [JSONDictionary]
return dictionaries.flatMap(Pokemon.init)
}
WebService().load(resource: pokemonResource) { pokemons in
print(pokemons!)
}
class EmptyViewController : UIViewController {
var message :String!
init(message :String) {
super.init(nibName: nil, bundle: nil)
self.message = message
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func viewDidLoad() {
super.viewDidLoad()
self.view.backgroundColor = UIColor.green
let messageLabel = UILabel(frame: CGRect(x: 0, y: 0, width: 300, height: 44))
messageLabel.text = self.message
self.view.addSubview(messageLabel)
}
}
class EmptyView : UIView {
init(delegate :UIViewController, message :String) {
super.init(frame: delegate.view.frame)
self.backgroundColor = UIColor.purple
let label = UILabel(frame: CGRect(x: 0, y: 0, width: 300, height: 44))
label.textColor = UIColor.white
label.text = message
self.addSubview(label)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
class PokemonTableViewController : UITableViewController {
var pokemons :[Pokemon]!
init() {
super.init(nibName: nil, bundle: nil)
self.pokemons = [Pokemon]()
populatePokemons()
}
private func populatePokemons() {
WebService().load(resource: pokemonResource) { pokemons in
if let pokemons = pokemons {
if pokemons.isEmpty {
self.view = EmptyView(delegate :self, message :"No Pokemons Found!")
}
}
}
}
init(pokemons :[Pokemon]) {
super.init(nibName: nil, bundle: nil)
self.pokemons = pokemons
}
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.pokemons.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = UITableViewCell(style: .default, reuseIdentifier: "Cell")
cell.textLabel?.text = self.pokemons[indexPath.row].name
return cell
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func viewDidLoad() {
super.viewDidLoad()
self.view.backgroundColor = UIColor.white
}
}
class ContainerViewController : UIViewController {
init<T>(resource :Resource<T>, build:@escaping (T) -> UIViewController) {
super.init(nibName: nil, bundle: nil)
WebService().load(resource: resource) { result in
let content = build(result!)
self.add(content :content)
}
}
private func add(content :UIViewController) {
// Remove any existing child controllers.
for child in childViewControllers {
child.willMove(toParentViewController: nil)
child.view.removeFromSuperview()
child.removeFromParentViewController()
}
addChildViewController(content)
content.view.frame = self.view.bounds
content.view.translatesAutoresizingMaskIntoConstraints = false
self.view.addSubview(content.view)
content.view.leftAnchor.constraint(equalTo: view.leftAnchor).isActive = true
content.view.rightAnchor.constraint(equalTo: view.rightAnchor).isActive = true
content.view.topAnchor.constraint(equalTo: view.topAnchor).isActive = true
content.view.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true
content.didMove(toParentViewController: self)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
let containerVC = ContainerViewController(resource: pokemonResource) { pokemons in
if pokemons.isEmpty {
return EmptyViewController(message : "No Pokemons Found!")
} else {
return PokemonTableViewController(pokemons :pokemons)
}
}
let pokemonTVC = PokemonTableViewController()
PlaygroundSupport.PlaygroundPage.current.liveView = containerVC
PlaygroundSupport.PlaygroundPage.current.needsIndefiniteExecution = true
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment