|
// |
|
// UIViewController+RxLifecycleSwizzle |
|
// |
|
// Created by Herman Banken on 25/08/16. |
|
// Copyright © 2016 Q42. All rights reserved. |
|
// |
|
|
|
import Foundation |
|
import UIKit |
|
import RxSwift |
|
|
|
var lifecycleSubjectContext: UInt8 = 0 |
|
|
|
// MARK: - Subject Containers |
|
|
|
class ViewControllerLifeCycleObservable { |
|
let visibleSubject = ReplaySubject<Bool>.create(bufferSize: 1) |
|
let willBeVisibleSubject = ReplaySubject<Bool>.create(bufferSize: 1) |
|
|
|
func viewWillAppear() { |
|
willBeVisibleSubject.on(.Next(true)) |
|
} |
|
func viewDidAppear() { |
|
visibleSubject.on(.Next(true)) |
|
} |
|
func viewWillDisappear() { |
|
willBeVisibleSubject.on(.Next(false)) |
|
} |
|
func viewDidDisappear() { |
|
visibleSubject.on(.Next(false)) |
|
} |
|
deinit { |
|
visibleSubject.on(.Completed) |
|
willBeVisibleSubject.on(.Completed) |
|
} |
|
} |
|
|
|
// MARK: - Method Swizzling |
|
|
|
extension UIViewController { |
|
public override class func initialize() { |
|
struct Static { |
|
static var token: dispatch_once_t = 0 |
|
} |
|
|
|
// make sure this isn't a subclass |
|
if self !== UIViewController.self { |
|
return |
|
} |
|
|
|
func swizzle(original: Selector, _ replacement: Selector) { |
|
let originalMethod = class_getInstanceMethod(self, original) |
|
let swizzledMethod = class_getInstanceMethod(self, replacement) |
|
let didAddMethod = class_addMethod(self, original, method_getImplementation(swizzledMethod), method_getTypeEncoding(swizzledMethod)) |
|
if didAddMethod { |
|
class_replaceMethod(self, replacement, method_getImplementation(originalMethod), method_getTypeEncoding(originalMethod)) |
|
} else { |
|
method_exchangeImplementations(originalMethod, swizzledMethod) |
|
} |
|
} |
|
|
|
dispatch_once(&Static.token) { |
|
swizzle(#selector(UIViewController.viewWillAppear(_:)), #selector(UIViewController.rxlifecycle_viewWillAppear(_:))) |
|
swizzle(#selector(UIViewController.viewWillDisappear(_:)), #selector(UIViewController.rxlifecycle_viewWillDisappear(_:))) |
|
swizzle(#selector(UIViewController.viewDidAppear(_:)), #selector(UIViewController.rxlifecycle_viewDidAppear(_:))) |
|
swizzle(#selector(UIViewController.viewDidDisappear(_:)), #selector(UIViewController.rxlifecycle_viewDidDisappear(_:))) |
|
} |
|
} |
|
|
|
// MARK: - Shiny new Observable properties |
|
|
|
public var rx_visible: Observable<Bool> { |
|
return rx_synchronized { |
|
if let lifecycleObservable = objc_getAssociatedObject(self, &lifecycleSubjectContext) as? ViewControllerLifeCycleObservable { |
|
return lifecycleObservable.visibleSubject |
|
} |
|
|
|
let lifecycleObservable = ViewControllerLifeCycleObservable() |
|
|
|
objc_setAssociatedObject(self, &lifecycleSubjectContext, lifecycleObservable, .OBJC_ASSOCIATION_RETAIN_NONATOMIC) |
|
return lifecycleObservable.visibleSubject |
|
} |
|
} |
|
|
|
public var rx_willBeVisible: Observable<Bool> { |
|
return rx_synchronized { |
|
if let lifecycleObservable = objc_getAssociatedObject(self, &lifecycleSubjectContext) as? ViewControllerLifeCycleObservable { |
|
return lifecycleObservable.willBeVisibleSubject |
|
} |
|
|
|
let lifecycleObservable = ViewControllerLifeCycleObservable() |
|
|
|
objc_setAssociatedObject(self, &lifecycleSubjectContext, lifecycleObservable, .OBJC_ASSOCIATION_RETAIN_NONATOMIC) |
|
return lifecycleObservable.willBeVisibleSubject |
|
} |
|
} |
|
|
|
public var rx_willAppear: Observable<Void> { return rx_willBeVisible.filter { $0 }.map { _ in Void() } } |
|
public var rx_willDisappear: Observable<Void> { return rx_willBeVisible.filter { !$0 }.map { _ in Void() } } |
|
public var rx_appear: Observable<Void> { return rx_visible.filter { $0 }.map { _ in Void() } } |
|
public var rx_disappear: Observable<Void> { return rx_visible.filter { !$0 }.map { _ in Void() } } |
|
|
|
// MARK: - Swizzled Methods |
|
|
|
func rxlifecycle_viewWillAppear(animated: Bool) { |
|
self.rxlifecycle_viewWillAppear(animated) |
|
if let lifecycleObservable = objc_getAssociatedObject(self, &lifecycleSubjectContext) as? ViewControllerLifeCycleObservable { |
|
lifecycleObservable.viewWillAppear() |
|
} |
|
} |
|
|
|
func rxlifecycle_viewWillDisappear(animated: Bool) { |
|
self.rxlifecycle_viewWillDisappear(animated) |
|
if let lifecycleObservable = objc_getAssociatedObject(self, &lifecycleSubjectContext) as? ViewControllerLifeCycleObservable { |
|
lifecycleObservable.viewWillDisappear() |
|
} |
|
} |
|
|
|
func rxlifecycle_viewDidAppear(animated: Bool) { |
|
self.rxlifecycle_viewDidAppear(animated) |
|
if let lifecycleObservable = objc_getAssociatedObject(self, &lifecycleSubjectContext) as? ViewControllerLifeCycleObservable { |
|
lifecycleObservable.viewDidAppear() |
|
} |
|
} |
|
|
|
func rxlifecycle_viewDidDisappear(animated: Bool) { |
|
self.rxlifecycle_viewDidDisappear(animated) |
|
if let lifecycleObservable = objc_getAssociatedObject(self, &lifecycleSubjectContext) as? ViewControllerLifeCycleObservable { |
|
lifecycleObservable.viewDidDisappear() |
|
} |
|
} |
|
} |
|
|
|
extension NSObject { |
|
func rx_synchronized<T>(@noescape action: () -> T) -> T { |
|
objc_sync_enter(self) |
|
let result = action() |
|
objc_sync_exit(self) |
|
return result |
|
} |
|
} |