You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Swift 4中如何将Type作为变量进行传递?

Solution: Use Generics for Type-Safe View Controller Instantiation

Great question! The key here is to use generics in Swift, which lets you pass a view controller type as a parameter while maintaining type safety—something your Any approach can't handle reliably. Here's how to refactor your code cleanly:

Basic Generic Function

First, create a generic function that accepts a view controller type, handles the storyboard instantiation, and returns a strongly typed instance:

func instantiateViewController<T: UIViewController>(
    ofType type: T.Type,
    withIdentifier identifier: String,
    fromStoryboard storyboardName: String = "Main"
) -> T {
    let storyboard = UIStoryboard(name: storyboardName, bundle: nil)
    // Use guard to safely cast and provide a meaningful error if something goes wrong
    guard let viewController = storyboard.instantiateViewController(withIdentifier: identifier) as? T else {
        fatalError("Failed to instantiate view controller with identifier \(identifier) as \(type) from \(storyboardName) storyboard")
    }
    return viewController
}

How to Use It

Call the function by passing your view controller's type (using .self) and its storyboard identifier:

let mapVC = instantiateViewController(ofType: MapViewController.self, withIdentifier: "MapViewController")

Simplified Version (If Identifier Matches Class Name)

If your storyboard identifiers match your view controller class names (a common best practice), you can eliminate the identifier parameter entirely by deriving it from the type:

func instantiateViewController<T: UIViewController>(
    ofType type: T.Type,
    fromStoryboard storyboardName: String = "Main"
) -> T {
    let identifier = String(describing: type)
    let storyboard = UIStoryboard(name: storyboardName, bundle: nil)
    
    guard let viewController = storyboard.instantiateViewController(withIdentifier: identifier) as? T else {
        fatalError("Failed to instantiate \(identifier) from \(storyboardName) storyboard")
    }
    return viewController
}

Even Cleaner Call

Now you don't need to repeat the identifier:

let mapVC = instantiateViewController(ofType: MapViewController.self)

Swifty Extension Approach

For even better integration with Swift's style, extend UIStoryboard to add this functionality directly:

extension UIStoryboard {
    static func instantiateViewController<T: UIViewController>(
        ofType type: T.Type,
        fromStoryboard storyboardName: String = "Main"
    ) -> T {
        let identifier = String(describing: type)
        let storyboard = UIStoryboard(name: storyboardName, bundle: nil)
        
        guard let viewController = storyboard.instantiateViewController(withIdentifier: identifier) as? T else {
            fatalError("Failed to instantiate \(identifier) from \(storyboardName) storyboard")
        }
        return viewController
    }
}

Usage with Extension

let mapVC = UIStoryboard.instantiateViewController(ofType: MapViewController.self)

Why This Works

  • Generics: The T: UIViewController constraint ensures we only accept valid view controller types, and T.Type lets us pass the class itself as a parameter.
  • Type Safety: Unlike using Any, this approach gives you compile-time checks and avoids unsafe as! casts without meaningful error handling.
  • Reusability: You can now use this function/extension for any view controller in your app, eliminating repetitive storyboard instantiation code.

内容的提问来源于stack exchange,提问作者Scott Robinson

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 03:55:19