Last active
April 23, 2018 12:08
-
-
Save andreasmpet/cb88410bba140145e0ea767fa6da3a1a to your computer and use it in GitHub Desktop.
ViewControllerLifeCycleEventHandler
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 | |
struct HideNavBehavior: ViewControllerLifecycleBehavior { | |
func handle(event: LifecycleEvent) { | |
switch event.eventType { | |
case .willAppear: | |
event.viewController.navigationController?.setNavigationBarHidden(true, animated: false) | |
case .willDisappear: | |
event.viewController.navigationController?.setNavigationBarHidden(false, animated: false) | |
default: | |
break | |
} | |
} | |
} | |
class ExampleViewController: UIViewController { | |
override func viewDidLoad() { | |
super.viewDidLoad() | |
self.hero.isEnabled = true | |
self.set(behaviors: [ | |
CodeBlockBehavior(eventType: .didLayoutSubviews, isOneshot: true, block: { [weak self] in | |
// Code that should only run after first layout | |
}), | |
CodeBlockBehavior(eventType: .didAppear, isOneshot: true, block: { [weak self] in | |
// Code that should only run after first viewDidAppear. For example screen view tracking | |
}), | |
HideNavBehavior() | |
]) | |
} | |
} |
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
// Inspiration: http://irace.me/lifecycle-behaviors | |
import UIKit | |
typealias BlockLifecycleEventHandlerBlock = (_ viewController: UIViewController) -> Void | |
class CodeBlockBehavior: ViewControllerLifecycleBehavior { | |
let eventType: LifecycleEvent.EventType | |
let block: BlockLifecycleEventHandlerBlock | |
let isOneshot: Bool | |
var hasFired: Bool = false | |
init(eventType: LifecycleEvent.EventType, isOneshot: Bool, block: @escaping BlockLifecycleEventHandlerBlock) { | |
self.eventType = eventType | |
self.isOneshot = isOneshot | |
self.block = block | |
} | |
func handle(event: LifecycleEvent) { | |
if event.eventType == self.eventType { | |
let canFire = !(self.isOneshot && self.hasFired) | |
if canFire { | |
self.block(event.viewController) | |
self.hasFired = true | |
} | |
} | |
} | |
} | |
struct LifecycleEvent { | |
enum EventType { | |
case didLoad | |
case willAppear | |
case didAppear | |
case willDisappear | |
case didDisappear | |
case willLayoutSubviews | |
case didLayoutSubviews | |
} | |
let eventType: EventType | |
let viewController: UIViewController | |
} | |
protocol ViewControllerLifecycleBehavior { | |
func handle(event: LifecycleEvent) | |
} | |
extension UIViewController { | |
func set(behaviors: [ViewControllerLifecycleBehavior]) { | |
let behaviorViewController = LifecycleBehaviorViewController(behaviors: behaviors) | |
addChildViewController(behaviorViewController) | |
view.addSubview(behaviorViewController.view) | |
behaviorViewController.didMove(toParentViewController: 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 | |
self.broadcastEvent(lifecycleEvent: self.event(ofType: .didLoad)) | |
} | |
override func viewWillAppear(_ animated: Bool) { | |
super.viewWillAppear(animated) | |
self.broadcastEvent(lifecycleEvent: self.event(ofType: .willAppear)) | |
} | |
override func viewDidAppear(_ animated: Bool) { | |
super.viewDidAppear(animated) | |
self.broadcastEvent(lifecycleEvent: self.event(ofType: .didAppear)) | |
} | |
override func viewWillDisappear(_ animated: Bool) { | |
super.viewWillDisappear(animated) | |
self.broadcastEvent(lifecycleEvent: self.event(ofType: .willDisappear)) | |
} | |
override func viewDidDisappear(_ animated: Bool) { | |
super.viewDidDisappear(animated) | |
self.broadcastEvent(lifecycleEvent: self.event(ofType: .didDisappear)) | |
} | |
override func viewWillLayoutSubviews() { | |
super.viewWillLayoutSubviews() | |
self.broadcastEvent(lifecycleEvent: self.event(ofType: .willLayoutSubviews)) | |
} | |
override func viewDidLayoutSubviews() { | |
super.viewDidLayoutSubviews() | |
self.broadcastEvent(lifecycleEvent: self.event(ofType: .didLayoutSubviews)) | |
} | |
// MARK: - Private | |
private func broadcastEvent(lifecycleEvent: LifecycleEvent) { | |
self.behaviors.forEach({ $0.handle(event: lifecycleEvent )}) | |
} | |
private func event(ofType type: LifecycleEvent.EventType) -> LifecycleEvent { | |
return LifecycleEvent(eventType: type, viewController: self.parent!) | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment