Created
June 6, 2020 11:12
-
-
Save asobolevsky/499f351f039169edc008d5b81356424d 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 | |
protocol ViewControllerLifecycleBehavior { | |
func afterLoading(_ viewController: UIViewController) | |
func beforeAppearing(_ viewController: UIViewController) | |
func afterAppearing(_ viewController: UIViewController) | |
func beforeDisappearing(_ viewController: UIViewController) | |
func afterDisappearing(_ viewController: UIViewController) | |
func beforeLayingOutSubviews(_ viewController: UIViewController) | |
func afterLayingOutSubviews(_ viewController: UIViewController) | |
} | |
extension ViewControllerLifecycleBehavior { | |
func afterLoading(_ viewController: UIViewController) {} | |
func beforeAppearing(_ viewController: UIViewController) {} | |
func afterAppearing(_ viewController: UIViewController) {} | |
func beforeDisappearing(_ viewController: UIViewController) {} | |
func afterDisappearing(_ viewController: UIViewController) {} | |
func beforeLayingOutSubviews(_ viewController: UIViewController) {} | |
func afterLayingOutSubviews(_ viewController: UIViewController) {} | |
} | |
extension UIViewController { | |
/* | |
Add behaviors to be hooked into this view controller’s lifecycle. | |
This method requires the view controller’s view to be loaded, so it’s best to call | |
in `viewDidLoad` to avoid it being loaded prematurely. | |
- parameter behaviors: Behaviors to be added. | |
*/ | |
func addBehaviors(behaviors: [ViewControllerLifecycleBehavior]) { | |
let behaviorViewController = LifecycleBehaviorViewController(behaviors: behaviors) | |
addChild(behaviorViewController) | |
view.addSubview(behaviorViewController.view) | |
behaviorViewController.didMove(toParent: self) | |
} | |
private final class LifecycleBehaviorViewController: UIViewController { | |
private let behaviors: [ViewControllerLifecycleBehavior] | |
// MARK: - Initialization | |
init(behaviors: [ViewControllerLifecycleBehavior]) { | |
self.behaviors = behaviors | |
super.init(nibName: nil, bundle: nil) | |
} | |
required init?(coder aDecoder: NSCoder) { | |
fatalError("init(coder:) has not been implemented") | |
} | |
// MARK: - UIViewController | |
override func viewDidLoad() { | |
super.viewDidLoad() | |
view.isHidden = true | |
applyBehaviors { behavior, viewController in | |
behavior.afterLoading(viewController) | |
} | |
} | |
override func viewWillAppear(_ animated: Bool) { | |
super.viewWillAppear(animated) | |
applyBehaviors { behavior, viewController in | |
behavior.beforeAppearing(viewController) | |
} | |
} | |
override func viewDidAppear(_ animated: Bool) { | |
super.viewDidAppear(animated) | |
applyBehaviors { behavior, viewController in | |
behavior.afterAppearing(viewController) | |
} | |
} | |
override func viewWillDisappear(_ animated: Bool) { | |
super.viewWillDisappear(animated) | |
applyBehaviors { behavior, viewController in | |
behavior.beforeDisappearing(viewController) | |
} | |
} | |
override func viewDidDisappear(_ animated: Bool) { | |
super.viewDidDisappear(animated) | |
applyBehaviors { behavior, viewController in | |
behavior.afterDisappearing(viewController) | |
} | |
} | |
override func viewWillLayoutSubviews() { | |
super.viewWillLayoutSubviews() | |
applyBehaviors { behavior, viewController in | |
behavior.beforeLayingOutSubviews(viewController) | |
} | |
} | |
override func viewDidLayoutSubviews() { | |
super.viewDidLayoutSubviews() | |
applyBehaviors { behavior, viewController in | |
behavior.afterLayingOutSubviews(viewController) | |
} | |
} | |
// MARK: - Private | |
private func applyBehaviors(body: (_ behavior: ViewControllerLifecycleBehavior, _ viewController: UIViewController) -> ()) { | |
guard let parentViewController = parent else { return } | |
for behavior in behaviors { | |
body(behavior, parentViewController) | |
} | |
} | |
} | |
} | |
typealias BehaviorClosure = (_ viewController: UIViewController) -> () | |
// MARK: - ViewControllerLifecycle | |
enum ViewControllerLifecycle : CaseIterable { | |
typealias AllCases = [ViewControllerLifecycle] | |
case afterLoading(BehaviorClosure?) | |
case afterAppearing(BehaviorClosure?) | |
case beforeAppearing(BehaviorClosure?) | |
case beforeDisappearing(BehaviorClosure?) | |
case afterDisappearing(BehaviorClosure?) | |
case beforeLayingOutSubviews(BehaviorClosure?) | |
case afterLayingOutSubviews(BehaviorClosure?) | |
static var allCases: [ViewControllerLifecycle] { | |
return [afterLoading(nil), | |
beforeAppearing(nil), | |
beforeDisappearing(nil), | |
beforeLayingOutSubviews(nil), | |
afterLayingOutSubviews(nil)] | |
} | |
} | |
// MARK: - createAnonimousBehavior | |
func createAnonimousBehavior(with lifecycle: [ViewControllerLifecycle]) -> ViewControllerLifecycleBehavior { | |
class AnonimousBehavior: ViewControllerLifecycleBehavior { | |
private var lifeCycle: [ViewControllerLifecycle] | |
init(lifeCycle:[ViewControllerLifecycle]) { | |
self.lifeCycle = lifeCycle | |
} | |
func afterLoading(_ viewController: UIViewController) { | |
lifeCycle.forEach { | |
guard case .afterLoading(let closure) = $0 else { return } | |
closure?(viewController) | |
} | |
} | |
func afterAppearing(_ viewController: UIViewController) { | |
lifeCycle.forEach { | |
guard case .afterAppearing(let closure) = $0 else { return } | |
closure?(viewController) | |
} | |
} | |
func beforeAppearing(_ viewController: UIViewController) { | |
lifeCycle.forEach { | |
guard case .beforeAppearing(let closure) = $0 else { return } | |
closure?(viewController) | |
} | |
} | |
func beforeDisappearing(_ viewController: UIViewController) { | |
lifeCycle.forEach { | |
guard case .beforeDisappearing(let closure) = $0 else { return } | |
closure?(viewController) | |
} | |
} | |
func afterDisappearing(_ viewController: UIViewController) { | |
lifeCycle.forEach { | |
guard case .afterDisappearing(let closure) = $0 else { return } | |
closure?(viewController) | |
} | |
} | |
func beforeLayingOutSubviews(_ viewController: UIViewController) { | |
lifeCycle.forEach { | |
guard case .beforeLayingOutSubviews(let closure) = $0 else { return } | |
closure?(viewController) | |
} | |
} | |
func afterLayingOutSubviews(_ viewController: UIViewController) { | |
lifeCycle.forEach { | |
guard case .afterLayingOutSubviews(let closure) = $0 else { return } | |
closure?(viewController) | |
} | |
} | |
} | |
let behavior = AnonimousBehavior(lifeCycle: ViewControllerLifecycle.allCases) | |
return behavior | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment