From 7a7e5923e9c47b3ea8738c340cb14ebdfaaf774f Mon Sep 17 00:00:00 2001 From: Nam Kennic Date: Tue, 2 Jun 2020 13:46:07 +0700 Subject: [PATCH] Auto swizzles dismiss method --- Example/DialogViewController.swift | 8 +-- NKModalPresenter.podspec | 2 +- NKModalPresenter/NKModalPresenter.swift | 80 ++++++++++++++----------- 3 files changed, 46 insertions(+), 44 deletions(-) diff --git a/Example/DialogViewController.swift b/Example/DialogViewController.swift index 5d7b1fa..2321992 100644 --- a/Example/DialogViewController.swift +++ b/Example/DialogViewController.swift @@ -103,13 +103,7 @@ class DialogViewController: UIViewController { override func dismiss(animated flag: Bool, completion: (() -> Void)? = nil) { _ = view.endEditing(true) - - if let controller = modalController { - controller.dismiss(animated: flag, completion: completion) - } - else { - super.dismiss(animated: flag, completion: completion) - } + super.dismiss(animated: flag, completion: completion) } // MARK: - diff --git a/NKModalPresenter.podspec b/NKModalPresenter.podspec index d3edecb..ecdfdba 100644 --- a/NKModalPresenter.podspec +++ b/NKModalPresenter.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'NKModalPresenter' - s.version = '1.4.2' + s.version = '1.5.0' s.summary = 'Present UIViewController modally' s.description = <<-DESC Present UIViewController modally easily and beautifully with animation. diff --git a/NKModalPresenter/NKModalPresenter.swift b/NKModalPresenter/NKModalPresenter.swift index 6fe692d..b0d97b0 100644 --- a/NKModalPresenter/NKModalPresenter.swift +++ b/NKModalPresenter/NKModalPresenter.swift @@ -35,8 +35,8 @@ public class NKModalPresenter { let modalController = NKModalController(viewController: viewController) modalController.present(animate: animate, to: position) -// let classType = type(of: viewController) -// viewController.swizzleInstanceMethod(classType, from: #selector(classType.dismiss(animated:completion:)), to: #selector(classType.dismissModal(animated:completion:))) + let classType = type(of: viewController) + viewController.swizzleInstanceMethod(classType, from: #selector(classType.dismiss(animated:completion:)), to: #selector(classType.dismissModal(animated:completion:))) NotificationCenter.default.addObserver(self, selector: #selector(onModalControllerDismissed), name: NKModalController.didDismiss, object: modalController) activeModalControllers.append(modalController) @@ -97,8 +97,8 @@ extension UIViewController { } @objc public func dismissModal(animated: Bool, completion: (() -> Void)? = nil) { -// let classType = type(of: self) -// swizzleInstanceMethod(classType, from: #selector(classType.dismissModal(animated:completion:)), to: #selector(classType.dismiss(animated:completion:))) + let classType = type(of: self) + swizzleInstanceMethod(classType, from: #selector(classType.dismissModal(animated:completion:)), to: #selector(classType.dismiss(animated:completion:))) if let modal = modalController { modal.dismiss(animated: animated, completion: completion) @@ -112,35 +112,43 @@ extension UIViewController { // Swizzle methods -//extension UIViewController { -// -// private func _swizzleMethod(_ class_: AnyClass, from selector1: Selector, to selector2: Selector, isClassMethod: Bool) { -// let c: AnyClass -// if isClassMethod { -// guard let c_ = object_getClass(class_) else { return } -// c = c_ -// } -// else { -// c = class_ -// } -// -// guard let method1: Method = class_getInstanceMethod(c, selector1), -// let method2: Method = class_getInstanceMethod(c, selector2) else -// { -// return -// } -// -// if class_addMethod(c, selector1, method_getImplementation(method2), method_getTypeEncoding(method2)) { -// class_replaceMethod(c, selector2, method_getImplementation(method1), method_getTypeEncoding(method1)) -// } -// else { -// method_exchangeImplementations(method1, method2) -// } -// } -// -// /// Instance-method swizzling. -// fileprivate func swizzleInstanceMethod(_ class_: AnyClass, from sel1: Selector, to sel2: Selector) { -// _swizzleMethod(class_, from: sel1, to: sel2, isClassMethod: false) -// } -// -//} +extension UIViewController { + + func swizzleInstanceMethod(_ class_: AnyClass, from sel1: Selector, to sel2: Selector) { + DispatchQueue.once { + let originalMethod = class_getInstanceMethod(class_, sel1) + let swizzledMethod = class_getInstanceMethod(class_, sel2) + method_exchangeImplementations(originalMethod!, swizzledMethod!) + } + } + +} + +extension DispatchQueue { + private static var _onceTracker = [String]() + + public class func once(file: String = #file, function: String = #function, line: Int = #line, block:()->Void) { + let token = file + ":" + function + ":" + String(line) + once(token: token, block: block) + } + + /** + Executes a block of code, associated with a unique token, only once. The code is thread safe and will + only execute the code once even in the presence of multithreaded calls. + + - parameter token: A unique reverse DNS style name such as com.vectorform. or a GUID + - parameter block: Block to execute once + */ + public class func once(token: String, block:()->Void) { + objc_sync_enter(self) + defer { objc_sync_exit(self) } + + + if _onceTracker.contains(token) { + return + } + + _onceTracker.append(token) + block() + } +}