Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Return instancetype in Swift

I'm trying to make this extension:

extension UIViewController {     class func initialize(storyboardName: String, storyboardId: String) -> Self     {         let storyboad = UIStoryboard(name: storyboardName, bundle: nil)         let controller = storyboad.instantiateViewControllerWithIdentifier(storyboardId) as! Self          return controller     } } 

But I get compile error:

error: cannot convert return expression of type 'UIViewController' to return type 'Self'

Is it possible? Also I want to make it as init(storyboardName: String, storyboardId: String)

like image 579
ChikabuZ Avatar asked Oct 18 '15 16:10

ChikabuZ


1 Answers

Similar as in Using 'self' in class extension functions in Swift, you can define a generic helper method which infers the type of self from the calling context:

extension UIViewController {     class func instantiateFromStoryboard(storyboardName: String, storyboardId: String) -> Self     {         return instantiateFromStoryboardHelper(storyboardName, storyboardId: storyboardId)     }      private class func instantiateFromStoryboardHelper<T>(storyboardName: String, storyboardId: String) -> T     {         let storyboard = UIStoryboard(name: storyboardName, bundle: nil)         let controller = storyboard.instantiateViewControllerWithIdentifier(storyboardId) as! T         return controller     } } 

Then

let vc = MyViewController.instantiateFromStoryboard("name", storyboardId: "id") 

compiles, and the type is inferred as MyViewController.


Update for Swift 3:

extension UIViewController {     class func instantiateFromStoryboard(storyboardName: String, storyboardId: String) -> Self     {         return instantiateFromStoryboardHelper(storyboardName: storyboardName, storyboardId: storyboardId)     }      private class func instantiateFromStoryboardHelper<T>(storyboardName: String, storyboardId: String) -> T     {         let storyboard = UIStoryboard(name: storyboardName, bundle: nil)         let controller = storyboard.instantiateViewController(withIdentifier: storyboardId) as! T         return controller     } } 

Another possible solution, using unsafeDowncast:

extension UIViewController {     class func instantiateFromStoryboard(storyboardName: String, storyboardId: String) -> Self     {         let storyboard = UIStoryboard(name: storyboardName, bundle: nil)         let controller = storyboard.instantiateViewController(withIdentifier: storyboardId)         return unsafeDowncast(controller, to: self)     } } 
like image 80
Martin R Avatar answered Nov 06 '22 23:11

Martin R