5

I've static functions to instantiate view controllers that look like

class AController: UIViewController {
  static func instantiate() -> AController {
    let storyboard = UIStoryboard(name: "AController", bundle: nil)
    let controller = s.instantiateInitialViewController() as? AController
    return controller!
  }
}

class BController: UIViewController {
  static func instantiate() -> BController {
    let storyboard = UIStoryboard(name: "BController", bundle: nil)
    let controller = storyboard.instantiateInitialViewController() as? BController
    return controller!
  }
}

I've a bunch of them so I'd like to make that cleaner as:

class MYViewController: UIViewController {
  class func instantiate() -> self.type {
    let storyboard = UIStoryboard(name: "\(self.type)", bundle: nil)
    let controller = storyboard.instantiateInitialViewController() as? self.type
    return controller!
  }
}

class AController: MYViewController {
}

class BController: MYViewController {
}

But I don't know of to dynamically refer to the type of the object in a static / class function, and how to have this refer to the subclass when called from a subclass. It's easy to do once an object has been instantiated with type(of: object)

Guig
  • 9,891
  • 7
  • 64
  • 126
  • See http://stackoverflow.com/questions/33200035/return-instancetype-in-swift for a possible solution (but if the given answer works then it would be a simpler solution). – Martin R Dec 30 '16 at 15:28

1 Answers1

1

Try this:

class MYViewController: UIViewController {
    class func instantiate() -> Self {
        let storyboard = UIStoryboard(name: "\(self)", bundle: nil)
        let controller = storyboard.instantiateInitialViewController() as! Self
        return controller
    }
}

I'm not 100% sure it works because I didn't test your code directly (don't want to create a storyboard just for testing), but I wrote similar code to test it, which works:

class MYViewController: UIViewController {
    class func instantiate() -> Self {
        print("type: \(self)")
        return self.init()
    }
}
Ole Begemann
  • 135,006
  • 31
  • 278
  • 256
  • 1
    That does not compile in my Xcode 8.2.1: `'Self' is only available in a protocol or as the result of a method in a class; did you mean 'MYViewController'?` and `cannot convert return expression of type 'MYViewController' to return type 'Self'` – Martin R Dec 30 '16 at 15:27
  • weird that's compiling for me in 8.2.1. Exact build I have is 8C1002 – Guig Dec 30 '16 at 17:19
  • That is strange, I have double-checked in in a new project. The second code block compiles, but not the first. – Martin R Dec 30 '16 at 19:15
  • @MartinR: You're right, the `storyboard.instantiateInitialViewController() as! Self` part doesn't compile for me either. And the answers to the question you linked to (http://stackoverflow.com/questions/33200035/return-instancetype-in-swift) explain another solution (essentially, use generics). I honestly can't explain why it worked yesterday when I wrote the answer, although I could have sworn that I wrote this exact code in a playground and pasted it from there (the only thing I didn't do was run it with a storyboard; probably the playground got stuck). Sorry. – Ole Begemann Dec 31 '16 at 15:02
  • 1
    @OleBegemann maybe you had something like this `typealias \`Self\` = MYViewController`? – valdyr Jun 21 '17 at 16:18