0

I want to pass data from one view controller to another. And I am using the following code in the prepareForSegue to do so...

let detailVC: DetailVC = segue.destinationViewController as! DetailVC
detailVC.alertDict = sender as! NSDictionary

In the first line as you can see there is a ! after the as. Thats because I have to use it to force downcast, and if I do not include the ! then I get an error: UIViewController is not convertable to DetailVC. But DetailVC is a inheritance of UIViewController class, so why can it not convert? Here is the code for the class..

class DetailVC: UIViewController, MFMailComposeViewControllerDelegate, MFMessageComposeViewControllerDelegate {/*code*/}
1
  • segue.destinationViewController generally returns you a UIViewController object but DetailVC is another view controller with default + custom properties defined by you. So when you are getting the view controller from the segue you need to explicitly tell it to the compiler that this is a viewController of DetailVC type. Swift has a very strong type check mechanism to avoid runtime issues. Commented Feb 10, 2016 at 21:13

2 Answers 2

6

Think of it like this.

All DetailVCs are UIViewControllers, but not all UIViewControllers are DetailVCs.

Therefore, while you can freely convert a DetailVC to a UIViewController such as:

let detailVC = DetailVC()
let vc : UIViewController = detailVC as UIViewController

You cannot do the reverse, as the view controller might not be a DetailVC.

Therefore you can use as! in order to force the cast to the DetailVC.

let vc : UIViewController = DetailVC()
let detailVC = vc as! DetailVC

If it's a DetailVC, then it'll convert no problem; if it isn't, it will crash.

If you're not 100% sure of the type before you cast, you should always use as? in order to check the type before converting. For example:

let vc : UIViewController = DetailVC()

if let detailVC = vc as? DetailVC {
    // do something
}

Or, as user965972 says, you can go one step further by using a guard statement to prevent any further execution if the casting fails. For example:

let vc : UIViewController = DetailVC()

guard let detailVC = vc as? DetailVC else {
    // uh oh, casting failed. maybe do some error handling.
    return
}

// freely use detailVC from the this point onwards, with the correct type.

The method you use depends entirely on if you want to handle errors and whether further execution depends on the casting being successful.

Sign up to request clarification or add additional context in comments.

5 Comments

No you don't have to use the bang operator. as? is perfectly fine. You just get an optional and you either do the "if let" or do optional chaining "vc?... ".
@user965972 yup, edited to make a lil bit more clear.
very good. And now edit it to use a guard statement to improve it further. ;)
Thank you, makes sense and I will implement your suggestions. But why I look on online tutorials, they do not have to use the ? operator. Why is that?
@Harshil.Chokshi no problem :) I can only guess that in the tutorials you are using, it was clearly defined that the UIViewController was a DetailVC, or else they were just advocating bad practices! Much better to be safe about type casting though if you're in any doubt about the specific type of an object.
0

I assume you are getting a runtime error.

Make sure your view controller is set to the correct class in interface builder. If you first set the class in IB and then define the class in your code, IB will not find the class. You will notice this by looking at the "module" field under the "class" field in IB. It should not be "None", but something like the name of your project.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.