32

Am trying to downcast a view controller to a detail view controller but can't. Am using Core Data (for the first time). The error is in the prepareForSegue method and reads: "Could not cast value of type 'UIViewController' (0x1b81cdc) to 'Patternz.PatternDetailViewController' (0x32488). (lldb) "

Would appreciate an explanation of why it doesn't work. Here are the files.

ViewController.swift

import UIKit
import CoreData

class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {

    @IBOutlet weak var tableView: UITableView!

    var patterns : [Pattern] = []

    var selectedPattern : Pattern? = nil


    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
        self.tableView.dataSource = self
        self.tableView.delegate = self

        createTestPatterns()

        var context = (UIApplication.sharedApplication().delegate as! AppDelegate).managedObjectContext!

        var request = NSFetchRequest(entityName: "Pattern")

        var results = context.executeFetchRequest(request, error: nil)

        if results != nil {
            self.patterns = results! as! [Pattern]
        }
    }

    func createTestPatterns() {
        var context = (UIApplication.sharedApplication().delegate as! AppDelegate).managedObjectContext!

        var pattern = NSEntityDescription.insertNewObjectForEntityForName("Pattern", inManagedObjectContext: context) as! Pattern
        pattern.name = "Dress Shirt"
        pattern.frontimage = UIImageJPEGRepresentation(UIImage(named: "examplePattern.jpg"), 1)
        context.save(nil)
    }


    func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return self.patterns.count
    }

    func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
        var cell = UITableViewCell()
        var pattern = self.patterns[indexPath.row]
        cell.textLabel!.text = pattern.name
        cell.imageView!.image = UIImage(data: pattern.frontimage)
        return cell
    }

    func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
        self.selectedPattern = self.patterns[indexPath.row]
        self.performSegueWithIdentifier("patternDetailSegue", sender: self)
    }

    override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
        if segue.identifier == "patternDetailSegue" {
            var detailViewController = segue.destinationViewController as! PatternDetailViewController // Could not cast value of type 'UIViewController' to 'Patternz.PatternDetailViewController'
            detailViewController.pattern = self.selectedPattern
        }
    }



}

PatternDetailViewController.swift

import UIKit

class PatternDetailViewController: UIViewController {

    var pattern : Pattern? = nil

    override func viewDidLoad() {
        super.viewDidLoad()

        // Do any additional setup after loading the view.

        self.navigationItem.title = self.pattern!.name
    }



}
pdenlinger
  • 3,897
  • 10
  • 60
  • 92

8 Answers8

79

The problem, as you have said, is in these lines:

if segue.identifier == "patternDetailSegue" {
    var detailViewController = segue.destinationViewController as! PatternDetailViewController 
    // Could not cast value of type 'UIViewController' to 'Patternz.PatternDetailViewController'

The error message tells you that the destinationViewController of this segue is not, in fact, a PatternDetailViewController. You may think it is, but it isn't. You need to examine this segue in the storyboard and see what's really at the destination end of it.

The fact that the error message describes it as a UIViewController makes me suspect that you forgot to enter any view controller type in this view controller's Identity inspector in the storyboard:

Xcode Screenshot

Ronan Boiteau
  • 9,608
  • 6
  • 34
  • 56
matt
  • 515,959
  • 87
  • 875
  • 1,141
  • 1
    Yes, I forgot to enter the view controller type in the Storyboard. Once i fixed that, it worked. Thank you. – pdenlinger Jul 15 '15 at 21:14
  • 4
    Googled this question. Found this answer which worked for me. Went to upvote and realized I already did... – Greg Hilston May 23 '17 at 13:49
  • Something that's easy to overlook: `prepare(for segue: UIStoryboardSegue, sender: Any?)` (Swift 5 version) is called whenever there's a segue. It doesn't matter if you created it in storyboard or if you call `performSegue` in your code, as soon as you override `prepare`, it's always called. In the end you might get this error (even when everything's set up properly in the storyboard) because you don't check for all the possible identifiers for the segues of that specific `UIViewController`. – Neph Mar 09 '21 at 14:54
52

Adding to matt answer. Sometimes, you may also need to double check the custom class Module from the Identity inspector.

enter image description here

Your view controller need to belong to a specific Module. So make sure to select a Module from the list. In my case:

enter image description here

Malloc
  • 15,434
  • 34
  • 105
  • 192
7

It looks like you are using a navigation controller judging by your viewDidLoad() in PatternDetailViewController.

If PatternDetailViewController is embedded in a UINavigatonController then the navigation controller will be segue.destinationViewController.

Get the PatternDetailViewController like this:

let vc: UINavigationController = segue.destinationViewController as! UINavigationController
let detailVC = vc.topViewController as! PatternDetailViewController
detailVC.pattern = self.selectedPattern
Max
  • 1,143
  • 7
  • 7
2

This issue can happen if you copy Storyboard files from other project and did not change the Module . enter image description here

In the above image "EmployeeApp" is the old project name and the "clientTradingApp" is the new project name

Happy Coding :)

Ariven Nadar
  • 1,278
  • 13
  • 13
1

I solved the issue by following these steps:

  1. Find the source Scene in the storyboard. Go to Identity Inspector (Third tab in the right panel)
  2. Remove (Cut/ctrl+x) the "Class" under "Custom Class" from the Identity inspector.
  3. Switch to another scene.
  4. Switch back to source scene.
  5. Paste the custom class module you just removed.
  6. Exit XCode.
  7. Open Xcode.
  8. Clean.
  9. Build.

Why did it work? I was copy-pasting someone else's work. I probably wrote Class name in the right hand panel before there was a class with that name. My guess is Swift can not find these kinds of things dynamically. You have to behave like it wishes. You have to do certain things in a certain order.

Onat Korucu
  • 992
  • 11
  • 13
0

This just happened to me and I struggled for a couple hours following all the other posts here. In the end it turned out that my destination view controller file was missing the .swift extension. I hope this helps someone else!

Alaa Awad
  • 3,612
  • 6
  • 25
  • 35
0

My issue is:

Not work

let aBCViewController = UIViewController(nibName: "ABCViewController", bundle: nil) as! ABCViewController
present(aBCViewController, animated: true, completion: nil)

Work

let aBCViewController = ABCViewController(nibName: "ABCViewController", bundle: nil)
present(aBCViewController, animated: true, completion: nil)
William Hu
  • 15,423
  • 11
  • 100
  • 121
-1

Try clean Product > Clean

Edit: I came across the same error message and it was fixed using this method. This answer may not specifically answer the question

ninahadi
  • 432
  • 6
  • 9
  • From Review: Hi, this post does not seem to provide a [quality answer](https://stackoverflow.com/help/how-to-answer) to the question. Please either edit your answer and improve it, or just post it as a comment. – sɐunıɔןɐqɐp Oct 25 '18 at 07:03
  • Please explain why you think cleaning the build folder would fix this casting issue. – Eric Aya Oct 25 '18 at 10:53