Home > Software design >  Make variable data type accept all UIViewController subclass
Make variable data type accept all UIViewController subclass

Time:06-18

So I have many buttons, maybe up to 12, which is populated from a ForEach loop. And when each one is clicked, the button index will be passed as parameter to a function which will present a new ViewController based on the index of the button.

ForEach(0...11, id: \.self){ index in
    Button {
        openController(index: index)
    }, label: {
        Text("Button \(index)")
    }
}

Now in my openController function, I want to make my code as short as possible. So I will make a switch statement to determine the button clicked and open the respective viewcontroller.

So here's where my question comes in... I want to create just one variable which will be initialized by the respective Viewcontroller. But the problem comes when I declare the variable and try to initialize it.

For instance, since all the ViewControllers are subclasses of the UIViewController, I tried to declare the variable with a UIViewController data type before initializing it

func openController(index: Int){
    var viewController: UIViewController // declaring the variable
    switch index {
        case 0:
            viewController = ZeroViewController
        case 1:
            viewController = OneViewController
        // And it keeps going on till case 11
    }
    self.present(viewController, animated: true)
}

But I will be getting errors if I do that saying that I can't convert viewController which is of UIViewController type to ZeroViewController

So this will make my code bulky, because I'll have to create a variable for every Viewcontroller and also present it differently making my code look like this

func openController(index: Int){
    switch index {
        case 0:
            let viewController = ZeroViewController
            self.present(viewController, animated: true)
        case 1:
            let viewController = OneViewController
            self.present(viewController, animated: true)
        // And it keeps going on till case 11
    }
}

So is that the only option or is there a way I can shorten my code to look like the first function?

CodePudding user response:

Assuming you will also be setting properties in your "destination" view controllers...

If we have these two controllers:

class ZeroViewController: UIViewController {
    var testZero: String = ""
    override func viewDidLoad() {
        super.viewDidLoad()
        view.backgroundColor = .red
        print("test Zero:", testZero)
    }
}

class OneViewController: UIViewController {
    var testOne: String = ""
    override func viewDidLoad() {
        super.viewDidLoad()
        view.backgroundColor = .blue
        print("test One:", testOne)
    }
}

You can write your func like this:

func openController(index: Int) {
    var vc: UIViewController!
    switch index {
    case 0:
        let viewController = ZeroViewController()
        viewController.testZero = "Hello"
        vc = viewController
    case 1:
        let viewController = OneViewController()
        viewController.testOne = "Goodbye"
        vc = viewController
        // And it keeps going on till case 11
    default:
        return
    }
    self.present(vc, animated: true)
}

So, inside each case:

  • instantiate a view controller of the specific controller class
  • set any properties specific to that class
  • assign a reference to that instance to the vc var
  • then present vc
  • Related