Skip to content

Instantly share code, notes, and snippets.

@andreasmpet
Last active April 23, 2018 12:08
Show Gist options
  • Save andreasmpet/cb88410bba140145e0ea767fa6da3a1a to your computer and use it in GitHub Desktop.
Save andreasmpet/cb88410bba140145e0ea767fa6da3a1a to your computer and use it in GitHub Desktop.
ViewControllerLifeCycleEventHandler
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()
])
}
}
// 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