-3

I have formulated the function below so that I can re-use it in my ios app. However, I am unable to build my app because my function below has errors indicated to me but I cannot see what is wrong with it. The function is intended to move the user to a new page in the ios app. Please can someone advise?

 func goToPage(goto storyBoardId: String, ofType typeUIViewController: UIViewController.Type) -> UIViewController {
    let storyBoard: UIStoryboard = UIStoryboard.init(name: "Main", bundle: nil)
    let newPage = storyBoard.instantiateViewController(withIdentifier: storyBoardId) as! typeUIViewController // Error: use of undeclared type 'typeUIViewController'
    self.present(newPage, animated: true, completion: nil)

 return newPage
}
jamesMcKey
  • 481
  • 5
  • 28
  • 1
    From [this](https://developer.apple.com/library/content/documentation/DeveloperTools/Conceptual/debugging_with_xcode/Art/dwx-qs-12_2x.png) image. Look into the bottom right panel named 'console'. There you should look for things like 'reason', 'error', 'invalid', 'exception' and see what they are seeing and then search them and see if you can find answers to your questions. If you found an answer by searching for them, then delete this question. If you didn't then edit the question with the exact error and tell us what you tried by reading other answers, so we could suggest further steps... – mfaani Oct 16 '17 at 13:12

2 Answers2

1

Your function expects a return value of type UIViewController and you return nothing. So either return an instance you create (if you need one). Or remove return value.

There's a slightly modified variation of your function with generics, which does just what you want. The @discardableResult word before the function tells the compiler that the result can be omitted.

@discardableResult
func goToPage<T>(goto storyBoardId: String,
                 ofType typeUIViewController: T.Type) -> T
    where T: UIViewController {

    let storyboard = UIStoryboard(name: "Main", bundle: nil)
    let newPage = storyboard.instantiateViewController(withIdentifier: storyBoardId) as! T
    self.present(newPage, animated: true, completion: nil)

    return newPage
}

USAGE

// Ignore return value
goToPage(goto: "Page", ofType: ViewController.self)

// Preserve return value:
// Thanks to generics, page and page2 types are inferred by the compiler
// page is CustomController and page2 is LoginController
// and you can access corresponding interface:
var page = goToPage(goto: "Page", ofType: CustomController.self)
var page2 = goToPage(goto: "Page", ofType: LoginController.self)

Update

I see that Honey suggests the right idea, but the problem with typecasting still persists. The reason of that is that the compiler has no idea what kind of type typeUIViewController is. In fact, it is not actually even a type, it's only an inner name of the variable. And there is no way compiler could infer the type of it (to use with as operator). Hence, one of the proper ways to achieve what you are trying is by using generics. Consider generic T as a pattern which meets certain condition.

Hexfire
  • 5,945
  • 8
  • 32
  • 42
0

You need to change UIViewController to UIViewController.Type. For more see here

because a parameter of UIViewController can accept a UIViewController instance e.g. UIViewController(). However you need to get its type information (you don't need an instance), therefore it has to be a parameter of type UIViewController.Type so the value you pass can be something like SomeUIViewControllerSubclass.self which is NOT an instance...

So you have to do this:

 func goToPage(goto storyBoardId: String, ofType typeUIViewController: UIViewController.Type) -> UIViewController {
    let storyBoard: UIStoryboard = UIStoryboard.init(name: "Main", bundle: nil)
    let newPage = storyBoard.instantiateViewController(withIdentifier: storyBoardId) as! typeUIViewController
    self.present(newPage, animated: true, completion: nil)
}
mfaani
  • 33,269
  • 19
  • 164
  • 293