3
votes

I have some problems to use subclasses in Swift, hope someone can help me.

What I have

Two view controllers:

VC1 with just some UIButtons

EffectVC that do some animation depending on the button pressed on VC1

import UIKit

protocol viewAnimation {
    func initialStateSet()
    func finalStateSet()
}

class EffectVC: UIViewController {

    @IBOutlet weak var mainImage: UIImageView!

    override func viewDidLoad() {
        super.viewDidLoad()
        self.initialStateSet()
    }

    override func viewDidAppear(animated: Bool) {
        self.finalStateSet()
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
    }

    func initialStateSet() {
    }

    func finalStateSet() {
    }
}

class GrowingEffect : EffectVC, viewAnimation {

    override func initialStateSet() {
        // some stuff
    }

    override func finalStateSet() {
        // other stuff
    }
}

The problem

Maybe a simple question but I can't do what I want in Swift: I need to set a subclass according to the button that is pressed.

In other words I need to present subclassed view controller from my VC1 according to which button is pressed on VC1.

If I press the first button for example I want to show the VC 2 with the class GrowingEffect for use some custom stuff (this stuff must change according to the selected button).

What I tried

  1. use IBAction for create my subclassed VC2 and show it

    let storyboard = UIStoryboard(name: "Main", bundle: nil)

    let destinationViewController : UIViewController = storyboard.instantiateViewControllerWithIdentifier("EffectVC") as! GrowingEffect

    self.presentViewController(destinationViewController, animated: true, completion: nil)

but I got

Could not cast value of type 'ViewAnimationDemo.EffectVC' (0x109948570) to 'ViewAnimationDemo.GrowingEffect' (0x109948650).

  1. use PrepareForSegue

but I can't set any subclass

What I really want to do

I know there are some other solution, like not using storyboard, but now I describe exactly what I want to do, hoping this is possibile:

have only one view controller in IB (EffectVC) associate with the class EffectVC. The class EffectVC has some subclasses like GrowingEffect.

In my code I want to instantiate the view controller EffectVC with the subclass that I need: for example instantiate the view controller in IB EffectVC with the class GrowingEffect.

I know that if I have one view controller for every subclass of EffectVC I can do what I want but I don't want so many view controller in IB because they are equal, the only things that I want to change are 2 methods.

2

2 Answers

2
votes

I think there are some things mixed up in your setup. You should have 2 view controllers, each set up in its file, and each present in the storyboard with its identifier. It is ok if GrowingEffect inherits from EffectVC.

What you currently do with as! GrowingEffect is actually trying to cast the UIViewController instance you get from calling instantiateViewControllerWithIdentifier("EffectVC") to GrowingEffect. This will not work, because it is of type EffectVC.

Rather, you need to call instantiateViewControllerWithIdentifier("EffectVC") if button X is pressed, and instantiateViewControllerWithIdentifier("GrowingEffect") if button Y is pressed.

EDIT

If you use storyboard, you have to instantiate view controllers using instantiateViewControllerWithIdentifier. But you can only get an instance of GrowingEffect, if it is present on the storyboard.

It is not possible to "cast" an instance of EffectVC to GrowingEffect once created.

So, you have two possibilities here:

  1. Use storyboard and put both view controllers on it. Use instantiateViewControllerWithIdentifier to instantiate the view controller you need, depending on the button pressed.

  2. Do not use storyboard. Then you can create the needed view controller manually and use your UINavigationController's pushViewController method to present it.

2
votes

You can't cast from parent class to child class, parent class just doesn't have the capacity to know what the child is doing. You can however cast from a child to parent, so you would want to set your view controller as GrowingEffect, then cast it to Effect, but again there is no strong suit to doing this either unless some method needs the parent class and you are using the child class. It looks like you need a redesign of how you want your view controllers laid out. Now I am assuming you have 2 children, lets call GrowingEffect and ShrinkingEffect. In your designer, you set your 1 to GrowingEffect and the other to ShrinkingEffect and make sure they have unique identifiers. Then you can use your view to present an Effect, and pass in either of those objects.