0

For some reason my segue is not being performed. Here is my storyboard setup.

enter image description here

This code is being called in viewDidAppear of my root view controller. In the XCode debugger it says that the fetch request returned 0 results before failing on the last line due to unexpectedly finding nil. If it returned 0 results, why wouldn't my segue be performed?

    var fetchResult: [User] = []
    do {
        // Look for User entities in Core Data
        fetchResult = try context.fetch(User.fetchRequest()) as! [User]
    } catch {
        fatalError("Fetch error")
    }
    
    if fetchResult.count == 0 {
        // New user, calculate TDEE
        performSegue(withIdentifier: "toTDEE", sender: self)
    }
    if fetchResult.count > 1 {
        // ERROR: too many users
        fatalError("fetch count > 1")
    }

    let user = fetchResult.first! as User
chmorgan
  • 89
  • 5

2 Answers2

1

The call to performSegue(withIdentifier:,sender:) doesn't block the control flow. It's an asynchronous call that will make sure that UIKit eventually presents the new view controller. The code in your method will continue to execute, however.

As a result, it will encounter the last line let user = fetchResult.first! as User immediately afterwards. This will crash as fetchResult.first results is an optional and you force-unwrap it even though it is nil (the fetchResult is empty, after all). And this crash will happen even before UIKit has even started to present the new view controller.

As a general rule of thumb you should always use optional binding instead of force-unwrapping optionals. There's excellent reading about this topic in this answer: https://stackoverflow.com/a/32170457/10165733. I recommend you have a look at it.

Lutz
  • 1,734
  • 9
  • 18
0

here is your updated RootViewController code:

//Changed back to this method
override func viewDidAppear(_ animated: Bool) {
    setup()
}

func setup() {
    
    var fetchResult: [User] = []
    do {
        // Look for User entities in Core Data
        fetchResult = try context.fetch(User.fetchRequest()) as! [User]
    } catch {
        fatalError("Fetch error")
    }

    //Modified this with single if conditions
    if fetchResult.count == 0 {
        // New user, calculate TDEE
        performSegue(withIdentifier: "toTDEE", sender: self)
    } else if fetchResult.count > 1 {
        // ERROR: Too many users
        fatalError("fetch count > 1")
    } else {
        //if fetchResult.count == 1
        if let user = fetchResult.first { // New Edit Here
            if !user.didFinishSetup {
                // Didn't finish setup, re-calculate TDEE
                performSegue(withIdentifier: "toTDEE", sender: self)
            }
        }
    }
}

And HERE is your updated project for more info.

Dharmesh Kheni
  • 71,228
  • 33
  • 160
  • 165