import UIKit
/// 어떤 화면으로 popToView할 것인가 대한 옵션.
enum PopToViewOptions {
/// 이전화면.
case previous
/// 루트화면.
case root
}
/// Shared instance 생성 protocol.
protocol Shared {
static func shared() -> Self
}
extension Shared where Self: UIViewController {
/// 해당하는 UIViewController의 shared instance를 반환한다.
static func shared() -> Self {
let className = String(describing: self)
guard let resourcePath = Bundle.main.resourcePath else {return self.init()}
if let contents = FileManager.default.enumerator(atPath: resourcePath)?.allObjects as? [String] {
if let contentPath = contents.first(where: {$0.contains(className)}) {
let components = contentPath.components(separatedBy: "/")
if let componentPath = components.first(where: {$0.contains(".storyboardc")}) {
let storyBoardName = (componentPath as NSString).deletingPathExtension as String
let storyboard = UIStoryboard(name: storyBoardName, bundle: nil)
return storyboard.instantiateViewController(withIdentifier: className) as! Self
}
}
}
return self.init()
}
}
extension UIViewController: Shared {
/**
popViewController를 진행한다.
- parameter option: 어떤 화면으로 popToView할 것인가 대한 옵션.
- parameter animated: 애니메이션 여부.
*/
func pop(viewController option: PopToViewOptions, animated: Bool = true) {
guard let naviView = navigationController else {return}
switch option {
case .previous: naviView.popViewController(animated: animated)
case .root: naviView.popToRootViewController(animated: animated)
}
}
/**
popToViewController를 진행한다.
- parameter viewController: Pop하려는 viewController의 type.
- parameter animated: 애니메이션 여부.
- parameter configuration: Target viewController에 대한 설정부.
*/
func pop<T: UIViewController>(to viewController: T.Type, animated: Bool = true, configuration: ((T) -> ())? = nil) {
guard let naviView = navigationController else {return}
let viewController = viewController.shared()
configuration?(viewController)
naviView.popToViewController(viewController, animated: animated)
}
/**
PushViewController를 진행한다.
- parameter viewController: Push하려는 viewController의 type.
- parameter animated: 애니메이션 여부.
- parameter configuration: Target viewController에 대한 설정부.
*/
func push<T: UIViewController>(viewController: T.Type, animated: Bool = true, configuration: ((T) -> ())? = nil) {
guard let naviView = navigationController else {return}
let viewController = viewController.shared()
configuration?(viewController)
naviView.pushViewController(viewController, animated: animated)
}
/**
Presents a view controller modally.
- parameter viewController: Presents하려는 viewController의 type.
- parameter style: Transition style.
- parameter animated: 애니메이션 여부.
- parameter configuration: Target viewController에 대한 설정부.
- parameter completion: Presents completion.
*/
func present<T: UIViewController>(viewController: T.Type, style: UIModalTransitionStyle = .coverVertical, animated: Bool = true, configuration: ((T) -> ())? = nil, completion: (() -> Void)? = nil) {
let viewController = viewController.shared()
modalTransitionStyle = style
configuration?(viewController)
present(viewController, animated: animated, completion: completion)
}
}