Last active
June 6, 2020 11:08
-
-
Save asobolevsky/e56abfe65b877f417cf3f21d28b6e028 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 | |
typealias BehaviorClosure = (_ viewController: UIViewController) -> () | |
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) {} | |
} | |
func createAnonimousBehavior(afterLoading: BehaviorClosure? = nil, | |
beforeAppearing: BehaviorClosure? = nil, | |
afterAppearing: BehaviorClosure? = nil, | |
beforeDisappearing: BehaviorClosure? = nil, | |
afterDisappearing: BehaviorClosure? = nil, | |
beforeLayingOutSubviews: BehaviorClosure? = nil, | |
afterLayingOutSubviews: BehaviorClosure? = nil) -> ViewControllerLifecycleBehavior { | |
class AnonimousBehavior: ViewControllerLifecycleBehavior { | |
private var afterLoadingClosure: BehaviorClosure? | |
private var beforeAppearingClosure: BehaviorClosure? | |
private var afterAppearingClosure: BehaviorClosure? | |
private var beforeDisappearingClosure: BehaviorClosure? | |
private var afterDisappearingClosure: BehaviorClosure? | |
private var beforeLayingOutSubviewsClosure: BehaviorClosure? | |
private var afterLayingOutSubviewsClosure: BehaviorClosure? | |
init(afterLoading: BehaviorClosure? = nil, | |
beforeAppearing: BehaviorClosure? = nil, | |
afterAppearing: BehaviorClosure? = nil, | |
beforeDisappearing: BehaviorClosure? = nil, | |
afterDisappearing: BehaviorClosure? = nil, | |
beforeLayingOutSubviews: BehaviorClosure? = nil, | |
afterLayingOutSubviews: BehaviorClosure? = nil) { | |
self.afterLoadingClosure = afterLoading | |
self.beforeAppearingClosure = beforeAppearing | |
self.afterAppearingClosure = afterAppearing | |
self.beforeDisappearingClosure = beforeDisappearing | |
self.afterDisappearingClosure = afterDisappearing | |
self.beforeLayingOutSubviewsClosure = beforeLayingOutSubviews | |
self.afterLayingOutSubviewsClosure = afterLayingOutSubviews | |
} | |
func afterLoading(_ viewController: UIViewController) { | |
afterLoadingClosure?(viewController) | |
} | |
func beforeAppearing(_ viewController: UIViewController) { | |
beforeAppearingClosure?(viewController) | |
} | |
func afterAppearing(_ viewController: UIViewController) { | |
afterAppearingClosure?(viewController) | |
} | |
func beforeDisappearing(_ viewController: UIViewController) { | |
beforeDisappearingClosure?(viewController) | |
} | |
func afterDisappearing(_ viewController: UIViewController) { | |
afterDisappearingClosure?(viewController) | |
} | |
func beforeLayingOutSubviews(_ viewController: UIViewController) { | |
beforeLayingOutSubviewsClosure?(viewController) | |
} | |
func afterLayingOutSubviews(_ viewController: UIViewController) { | |
afterLayingOutSubviewsClosure?(viewController) | |
} | |
} | |
let behavior = AnonimousBehavior(afterLoading: afterLoading, | |
beforeAppearing: beforeAppearing, | |
afterAppearing: afterAppearing, | |
beforeDisappearing: beforeDisappearing, | |
afterDisappearing: afterDisappearing, | |
beforeLayingOutSubviews: beforeLayingOutSubviews, | |
afterLayingOutSubviews: afterLayingOutSubviews) | |
return behavior | |
} | |
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) | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment