From 8cd092e9287f779af08bce53dc3f1487b59908be Mon Sep 17 00:00:00 2001 From: Alexander Azarov Date: Sat, 28 Nov 2020 23:32:31 +0300 Subject: [PATCH] update playground for Swift 5 and Xcode 12 --- .../Contents.swift | 22 ++++---- .../Protocol.xcplaygroundpage/Contents.swift | 18 +++--- .../Contents.swift | 12 ++-- .../Sources/Helpers.swift | 55 +++++++++++++------ .../Sources/Networking.swift | 20 +++---- 5 files changed, 73 insertions(+), 54 deletions(-) diff --git a/Loading View Controllers.playground/Pages/Container View Controller.xcplaygroundpage/Contents.swift b/Loading View Controllers.playground/Pages/Container View Controller.xcplaygroundpage/Contents.swift index 8c98dcf..b57c290 100644 --- a/Loading View Controllers.playground/Pages/Container View Controller.xcplaygroundpage/Contents.swift +++ b/Loading View Controllers.playground/Pages/Container View Controller.xcplaygroundpage/Contents.swift @@ -6,16 +6,16 @@ import UIKit -let url = NSURL(string: "http://localhost:8000/episode.json")! +let url = URL(string: "http://localhost:8000/episode.json")! let episodeResource = Resource(url: url, parseJSON: { anyObject in (anyObject as? JSONDictionary).flatMap(Episode.init) }) final class LoadingViewController: UIViewController { - let spinner = UIActivityIndicatorView(activityIndicatorStyle: .Gray) + let spinner = UIActivityIndicatorView(style: .medium) - init(load: ((Result) -> ()) -> (), build: (A) -> UIViewController) { + init(load: (@escaping (Result) -> ()) -> (), build: @escaping (A) -> UIViewController) { super.init(nibName: nil, bundle: nil) spinner.startAnimating() load() { [weak self] result in @@ -28,7 +28,7 @@ final class LoadingViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() - view.backgroundColor = .whiteColor() + view.backgroundColor = .white spinner.hidesWhenStopped = true spinner.translatesAutoresizingMaskIntoConstraints = false view.addSubview(spinner) @@ -39,12 +39,12 @@ final class LoadingViewController: UIViewController { fatalError("init(coder:) has not been implemented") } - func add(content content: UIViewController) { - addChildViewController(content) + func add(content: UIViewController) { + addChild(content) view.addSubview(content.view) content.view.translatesAutoresizingMaskIntoConstraints = false content.view.constrainEdges(toMarginOf: view) - content.didMoveToParentViewController(self) + content.didMove(toParent: self) } } @@ -58,7 +58,7 @@ final class EpisodeDetailViewController: UIViewController { } override func viewDidLoad() { - view.backgroundColor = .whiteColor() + view.backgroundColor = .white view.addSubview(titleLabel) titleLabel.translatesAutoresizingMaskIntoConstraints = false @@ -70,11 +70,11 @@ final class EpisodeDetailViewController: UIViewController { let sharedWebservice = Webservice() let episodesVC = LoadingViewController(load: { callback in - sharedWebservice.load(episodeResource, completion: callback) + sharedWebservice.load(resource: episodeResource, completion: callback) }, build: EpisodeDetailViewController.init) episodesVC.view.frame = CGRect(x: 0, y: 0, width: 250, height: 300) -import XCPlayground -XCPlaygroundPage.currentPage.liveView = episodesVC +import PlaygroundSupport +PlaygroundPage.current.liveView = episodesVC diff --git a/Loading View Controllers.playground/Pages/Protocol.xcplaygroundpage/Contents.swift b/Loading View Controllers.playground/Pages/Protocol.xcplaygroundpage/Contents.swift index cda1eb5..7e705d9 100644 --- a/Loading View Controllers.playground/Pages/Protocol.xcplaygroundpage/Contents.swift +++ b/Loading View Controllers.playground/Pages/Protocol.xcplaygroundpage/Contents.swift @@ -6,7 +6,7 @@ import UIKit -let url = NSURL(string: "http://localhost:8000/episode.json")! +let url = URL(string: "http://localhost:8000/episode.json")! let episodeResource = Resource(url: url, parseJSON: { anyObject in (anyObject as? JSONDictionary).flatMap(Episode.init) }) @@ -24,27 +24,27 @@ protocol Loading { extension Loading where Self: UIViewController { func load(resource: Resource) { spinner.startAnimating() - sharedWebservice.load(resource) { [weak self] result in + sharedWebservice.load(resource: resource) { [weak self] result in self?.spinner.stopAnimating() guard let value = result.value else { return } // TODO loading error - self?.configure(value) + self?.configure(value: value) } } } final class EpisodeDetailViewController: UIViewController, Loading { - let spinner = UIActivityIndicatorView(activityIndicatorStyle: .Gray) + let spinner = UIActivityIndicatorView(style: .medium) let titleLabel = UILabel() convenience init(episode: Episode) { self.init() - configure(episode) + configure(value: episode) } convenience init(resource: Resource) { self.init() - load(resource) + load(resource: resource) } func configure(value: Episode) { @@ -53,7 +53,7 @@ final class EpisodeDetailViewController: UIViewController, Loading { override func viewDidLoad() { super.viewDidLoad() - view.backgroundColor = .whiteColor() + view.backgroundColor = .white spinner.hidesWhenStopped = true spinner.translatesAutoresizingMaskIntoConstraints = false @@ -71,5 +71,5 @@ let episodesVC = EpisodeDetailViewController(resource: episodeResource) episodesVC.view.frame = CGRect(x: 0, y: 0, width: 250, height: 300) -import XCPlayground -XCPlaygroundPage.currentPage.liveView = episodesVC +import PlaygroundSupport +PlaygroundPage.current.liveView = episodesVC diff --git a/Loading View Controllers.playground/Pages/Starting Point.xcplaygroundpage/Contents.swift b/Loading View Controllers.playground/Pages/Starting Point.xcplaygroundpage/Contents.swift index 9c09ae4..23fbd94 100644 --- a/Loading View Controllers.playground/Pages/Starting Point.xcplaygroundpage/Contents.swift +++ b/Loading View Controllers.playground/Pages/Starting Point.xcplaygroundpage/Contents.swift @@ -6,7 +6,7 @@ import UIKit -let url = NSURL(string: "http://localhost:8000/episode.json")! +let url = URL(string: "http://localhost:8000/episode.json")! let episodeResource = Resource(url: url, parseJSON: { anyObject in (anyObject as? JSONDictionary).flatMap(Episode.init) }) @@ -16,7 +16,7 @@ let sharedWebservice = Webservice() final class EpisodeDetailViewController: UIViewController { - let spinner = UIActivityIndicatorView(activityIndicatorStyle: .Gray) + let spinner = UIActivityIndicatorView(style: .medium) let titleLabel = UILabel() convenience init(episode: Episode) { @@ -27,7 +27,7 @@ final class EpisodeDetailViewController: UIViewController { convenience init(resource: Resource) { self.init() spinner.startAnimating() - sharedWebservice.load(resource) { [weak self] result in + sharedWebservice.load(resource: resource) { [weak self] result in self?.spinner.stopAnimating() guard let value = result.value else { return } // TODO loading error self?.titleLabel.text = value.title @@ -36,7 +36,7 @@ final class EpisodeDetailViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() - view.backgroundColor = .whiteColor() + view.backgroundColor = .white spinner.hidesWhenStopped = true spinner.translatesAutoresizingMaskIntoConstraints = false @@ -54,5 +54,5 @@ let episodesVC = EpisodeDetailViewController(resource: episodeResource) episodesVC.view.frame = CGRect(x: 0, y: 0, width: 250, height: 300) -import XCPlayground -XCPlaygroundPage.currentPage.liveView = episodesVC +import PlaygroundSupport +PlaygroundPage.current.liveView = episodesVC diff --git a/Loading View Controllers.playground/Sources/Helpers.swift b/Loading View Controllers.playground/Sources/Helpers.swift index 8e4b60c..aec563a 100644 --- a/Loading View Controllers.playground/Sources/Helpers.swift +++ b/Loading View Controllers.playground/Sources/Helpers.swift @@ -1,38 +1,57 @@ import UIKit extension UIView { - public func constrainEqual(attribute: NSLayoutAttribute, to: AnyObject, multiplier: CGFloat = 1, constant: CGFloat = 0) { - constrainEqual(attribute, to: to, attribute, multiplier: multiplier, constant: constant) + public func constrainEqual( + attribute: NSLayoutConstraint.Attribute, + to: AnyObject, + multiplier: CGFloat = 1, + constant: CGFloat = 0 + ) { + constrainEqual(attribute: attribute, to: to, attribute, multiplier: multiplier, constant: constant) } - public func constrainEqual(attribute: NSLayoutAttribute, to: AnyObject, _ toAttribute: NSLayoutAttribute, multiplier: CGFloat = 1, constant: CGFloat = 0) { - NSLayoutConstraint.activateConstraints([ - NSLayoutConstraint(item: self, attribute: attribute, relatedBy: .Equal, toItem: to, attribute: toAttribute, multiplier: multiplier, constant: constant) - ] - ) + public func constrainEqual( + attribute: NSLayoutConstraint.Attribute, + to: AnyObject, + _ toAttribute: NSLayoutConstraint.Attribute, + multiplier: CGFloat = 1, + constant: CGFloat = 0 + ) { + NSLayoutConstraint.activate([ + NSLayoutConstraint( + item: self, + attribute: attribute, + relatedBy: .equal, + toItem: to, + attribute: toAttribute, + multiplier: multiplier, + constant: constant + ) + ]) } public func constrainEdges(toMarginOf view: UIView) { - constrainEqual(.Top, to: view, .TopMargin) - constrainEqual(.Leading, to: view, .LeadingMargin) - constrainEqual(.Trailing, to: view, .TrailingMargin) - constrainEqual(.Bottom, to: view, .BottomMargin) + constrainEqual(attribute: .top, to: view, .topMargin) + constrainEqual(attribute: .leading, to: view, .leadingMargin) + constrainEqual(attribute: .trailing, to: view, .trailingMargin) + constrainEqual(attribute: .bottom, to: view, .bottomMargin) } public func center(inView view: UIView) { - centerXAnchor.constrainEqual(view.centerXAnchor) - centerYAnchor.constrainEqual(view.centerYAnchor) + centerXAnchor.constrainEqual(anchor: view.centerXAnchor) + centerYAnchor.constrainEqual(anchor: view.centerYAnchor) } } extension NSLayoutAnchor { - public func constrainEqual(anchor: NSLayoutAnchor, constant: CGFloat = 0) { - let constraint = constraintEqualToAnchor(anchor, constant: constant) - constraint.active = true + @objc public func constrainEqual(anchor: NSLayoutAnchor, constant: CGFloat = 0) { + constraint(equalTo: anchor, constant: constant).isActive = true } } -public func mainQueue(block: () -> ()) { - dispatch_async(dispatch_get_main_queue(), block) +public func mainQueue(block: @escaping () -> ()) { + DispatchQueue.main.async { + block() + } } diff --git a/Loading View Controllers.playground/Sources/Networking.swift b/Loading View Controllers.playground/Sources/Networking.swift index cec1734..72e509e 100644 --- a/Loading View Controllers.playground/Sources/Networking.swift +++ b/Loading View Controllers.playground/Sources/Networking.swift @@ -17,7 +17,7 @@ public typealias JSONDictionary = [String: AnyObject] extension Episode { public init?(json: JSONDictionary) { guard let id = json["id"] as? String, - title = json["title"] as? String else { return nil } + let title = json["title"] as? String else { return nil } self.id = id self.title = title @@ -26,15 +26,15 @@ extension Episode { public struct Resource { - public var url: NSURL - public var parse: NSData -> A? + public var url: URL + public var parse: (Data) -> A? } extension Resource { - public init(url: NSURL, parseJSON: AnyObject -> A?) { + public init(url: URL, parseJSON: @escaping (Any) -> A?) { self.url = url self.parse = { data in - let json = try? NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions()) + let json = try? JSONSerialization.jsonObject(with: data, options: JSONSerialization.ReadingOptions()) return json.flatMap(parseJSON) } } @@ -43,11 +43,11 @@ extension Resource { public enum Result { case success(A) - case error(ErrorType) + case error(Error) } extension Result { - public init(_ value: A?, or error: ErrorType) { + public init(_ value: A?, or error: Error) { if let value = value { self = .success(value) } else { @@ -62,7 +62,7 @@ extension Result { } -public enum WebserviceError: ErrorType { +public enum WebserviceError: Error { case other } @@ -71,8 +71,8 @@ public final class Webservice { public init() { } /// Loads a resource. The completion handler is always called on the main queue. - public func load(resource: Resource, completion: Result -> ()) { - NSURLSession.sharedSession().dataTaskWithURL(resource.url) { data, response, _ in + public func load(resource: Resource, completion: @escaping (Result) -> ()) { + URLSession.shared.dataTask(with: resource.url) { data, response, _ in let parsed = data.flatMap(resource.parse) let result = Result(parsed, or: WebserviceError.other) mainQueue { completion(result) }