Some extention code for viewContoller.


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)
    }
    
}