UIViewController扩展来从storyboard实例化

Nic*_* B. 11 iphone objective-c uiviewcontroller ios swift

我正在尝试在Swift中编写一个小扩展来处理UIViewController故事板中的实例化.

我的想法如下:由于UIStoryboard方法instantiateViewControllerWithIdentifier需要一个标识符来实例化给定的故事板的视图控制器,为什么不在我的故事板中为每个视图控制器分配一个等于其确切类名UserDetailViewController的标识符(即,将具有"UserDetailViewController"的标识符) "),并在UIViewController上创建一个类方法:

  • 接受UIStoryboard实例作为唯一参数
  • 将当前类名称作为字符串
  • instantiateViewControllerWithIdentifier使用类名作为参数调用storyboard实例
  • 获取新创建的UIViewController实例,然后返回它

所以,而不是(将类名重复为字符串,不是很好)

let vc = self.storyboard?.instantiateViewControllerWithIdentifier("UserDetailViewController") as UserDetailViewController
Run Code Online (Sandbox Code Playgroud)

这将是:

let vc = UserDetailViewController.instantiateFromStoryboard(self.storyboard!)
Run Code Online (Sandbox Code Playgroud)

我曾经在Objective-C中使用以下类别:

+ (instancetype)instantiateFromStoryboard:(UIStoryboard *)storyboard
{
    return [storyboard instantiateViewControllerWithIdentifier:NSStringFromClass([self class])];
}
Run Code Online (Sandbox Code Playgroud)

但我完全坚持使用Swift版本.我希望有某种方法可以做到这一点.我尝试了以下方法:

extension UIViewController {
    class func instantiateFromStoryboard(storyboard: UIStoryboard) -> Self {
        return storyboard.instantiateViewControllerWithIdentifier(NSStringFromClass(Self))
    }
}
Run Code Online (Sandbox Code Playgroud)

返回Self而不是AnyObject允许类型推断工作.否则,我将不得不抛出这种方法的每一次返回,这很烦人,但也许你有更好的解决方案?

这给我的错误:Use of unresolved identifier 'Self'NSStringFromClass部分似乎是问题.

你怎么看?

  • 有没有办法Self从课程功能返回?

  • 如果不需要每次都抛出返回值,你将如何工作?(即保持-> Self为返回值)

谢谢.

fin*_*all 26

如何写一个扩展UIStoryboard而不是UIViewController

extension UIStoryboard {
    func instantiateVC<T: UIViewController>() -> T? {
        // get a class name and demangle for classes in Swift
        if let name = NSStringFromClass(T.self)?.componentsSeparatedByString(".").last {
            return instantiateViewControllerWithIdentifier(name) as? T
        }
        return nil
    }

}
Run Code Online (Sandbox Code Playgroud)

即使采用这种方法,使用方的成本也很低.

let vc: UserDetailViewController? = aStoryboard.instantiateVC()
Run Code Online (Sandbox Code Playgroud)


Chi*_*buZ 7

感谢MartinR和他的回答,我知道答案:

更新:用协议重写.

实例化

protocol StringConvertible {
    var rawValue: String {get}
}

protocol Instantiable: class {
    static var storyboardName: StringConvertible {get}
}

extension Instantiable {
    static func instantiateFromStoryboard() -> Self {
        return instantiateFromStoryboardHelper()
    }

    private static func instantiateFromStoryboardHelper<T>() -> T {
        let identifier = String(describing: self)
        let storyboard = UIStoryboard(name: storyboardName.rawValue, bundle: nil)
        return storyboard.instantiateViewController(withIdentifier: identifier) as! T
    }
}

//MARK: -

extension String: StringConvertible { // allow string as storyboard name
    var rawValue: String {
        return self
    }
}
Run Code Online (Sandbox Code Playgroud)

STORYBOARDNAME

enum StoryboardName: String, StringConvertible {
    case main = "Main"
    //...
}
Run Code Online (Sandbox Code Playgroud)

用法:

class MyViewController: UIViewController, Instantiable {

    static var storyboardName: StringConvertible {
        return StoryboardName.main //Or you can use string value "Main"
    }
}

let viewController = MyController.instantiateFromStoryboard()
Run Code Online (Sandbox Code Playgroud)

  • 这个答案甚至比公认的要好 (2认同)

小智 5

UIViewController你可以像这样创建实例:

enum使用您所有的故事板名称进行创建。

enum AppStoryboard: String {
   case main = "Main"
   case profile = "Profile"
}
Run Code Online (Sandbox Code Playgroud)

然后,这是实例化的扩展UIViewController

extension UIViewController {

    class func instantiate<T: UIViewController>(appStoryboard: AppStoryboard) -> T {

        let storyboard = UIStoryboard(name: appStoryboard.rawValue, bundle: nil)
        let identifier = String(describing: self)
        return storyboard.instantiateViewController(withIdentifier: identifier) as! T
    }
}
Run Code Online (Sandbox Code Playgroud)

用法:

let profileVC: ProfileVC = ProfileVC.instantiate(appStoryboard: .profile)
self.navigationController?.pushViewController(profileVC,animated:true)
Run Code Online (Sandbox Code Playgroud)