Created
February 19, 2017 22:15
-
-
Save ryangibson/4ecdbde6789022cc0db578a246c3b184 to your computer and use it in GitHub Desktop.
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
import UIKit | |
import PlaygroundSupport | |
let cellIdentifier = "cellId" | |
let dataUrl = URL(string: "https://raw.githubusercontent.com/facebook/react-native/master/docs/MoviesExample.json")! | |
func contstraint(_ attr: NSLayoutAttribute, from: UIView, to: UIView) -> NSLayoutConstraint { | |
return NSLayoutConstraint( | |
item: from, | |
attribute: attr, | |
relatedBy: .equal, | |
toItem: to, | |
attribute: attr, | |
multiplier: 1, | |
constant: 1 | |
) | |
} | |
struct Movie { | |
let title: String | |
let thumbnail: URL | |
init?(json: [String : Any]) { | |
guard let title = json["title"] as? String, | |
let images = json["posters"] as? [String : String], | |
let tumbnailURLString = images["thumbnail"], | |
let thumbnailURL = URL(string: tumbnailURLString) | |
else { | |
return nil | |
} | |
self.title = title | |
self.thumbnail = thumbnailURL | |
} | |
} | |
func loadMovies(completionHandler: @escaping ([Movie]) -> Void) { | |
let task = URLSession(configuration: .default).dataTask(with: dataUrl) { (data, response, error) in | |
if let data = data { | |
do { | |
if let json = try JSONSerialization.jsonObject(with: data, options: .allowFragments) as? [String : Any], | |
let movies = json["movies"] as? [[String : Any]] | |
{ | |
completionHandler(movies.flatMap { Movie(json: $0) }) | |
} | |
} catch {} | |
} | |
} | |
task.resume() | |
} | |
extension UIImageView { | |
func loadImage(url: URL, placeholder: String) { | |
image = UIImage(named: placeholder) | |
_ = URLSession(configuration: .default).dataTask(with: url) { [weak self] (data, response, error) in | |
if let data = data, let img = UIImage(data: data) { | |
DispatchQueue.main.async { | |
self?.image = img | |
} | |
} else if let err = error { | |
print("Error: \(url) \(err)") | |
} else { | |
print("Error: \(url)") | |
} | |
}.resume() | |
} | |
} | |
class MovieCell: UITableViewCell { | |
init() { | |
super.init(style: .default, reuseIdentifier: cellIdentifier) | |
} | |
required init?(coder aDecoder: NSCoder) { fatalError("init(coder:) has not been implemented") } | |
} | |
class MoviesListViewController: UITableViewController { | |
var data: [Movie] | |
init(movies: [Movie]) { | |
data = movies | |
super.init(style: .plain) | |
} | |
required init?(coder aDecoder: NSCoder) { fatalError("init(coder:) has not been implemented") } | |
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { | |
tableView.deselectRow(at: indexPath, animated: true) | |
} | |
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { | |
return data.count | |
} | |
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { | |
let cell = makeCell(tableView) | |
cell.textLabel?.text = data[indexPath.row].title | |
cell.imageView?.loadImage(url: data[indexPath.row].thumbnail, placeholder: "placeholder") | |
return cell | |
} | |
func makeCell(_ tableView: UITableView) -> UITableViewCell { | |
guard let cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier) else { | |
return MovieCell() | |
} | |
return cell | |
} | |
} | |
class LoadingView: UIView { | |
var loadingLabel: UILabel = { | |
let label = UILabel() | |
label.text = "Loading..." | |
label.translatesAutoresizingMaskIntoConstraints = false | |
return label | |
}() | |
override init(frame: CGRect) { | |
super.init(frame: frame) | |
backgroundColor = UIColor.white | |
addSubview(loadingLabel) | |
addConstraints([ | |
contstraint(.centerX, from: loadingLabel, to: self), | |
contstraint(.centerY, from: loadingLabel, to: self), | |
]) | |
} | |
required init?(coder aDecoder: NSCoder) { fatalError("init(coder:) has not been implemented") } | |
} | |
class RootViewController: UIViewController { | |
var movieListVC: MoviesListViewController! = nil | |
override func viewDidLoad() { | |
super.viewDidLoad() | |
view = LoadingView(frame: view.frame) | |
view.backgroundColor = #colorLiteral(red: 0.8039215803, green: 0.8039215803, blue: 0.8039215803, alpha: 1) | |
} | |
func loadMoviesAndPresent() { | |
loadMovies() { [weak self] movies in | |
guard self != nil else { | |
return | |
} | |
print("Loaded \(movies.count) movies") | |
self!.movieListVC = MoviesListViewController(movies: movies) | |
self!.movieListVC.modalTransitionStyle = .crossDissolve | |
self!.show(self!.movieListVC, sender: self) | |
} | |
} | |
} | |
let rootVC = RootViewController(nibName: nil, bundle: nil) | |
rootVC.loadMoviesAndPresent() | |
PlaygroundPage.current.liveView = rootVC |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment