I am working on the Saving Locations Chapter of the MyLocations app, and get the error unexpectedly found nil , when I added the code setting the tab bar controller as the root in app Delegate, why is this happening and how can I solve this?
anyone? really need help
Hi @isaacballas2, looks like the tableview is returning nil and crashing because you are using forced unwrapping. One way to check this is by using a guard statement. In regards to a solution I would try changing the tabController constant to,
let tabController = mainStoryBoard.instantiateViewControllerWithIdentifier(“yourStoryboard”)
as! UITabBarController
self.window?.rootViewController = tabController
Best,
Gina
It won’t even compile, it says mainStoryboard is unknown identifier. I was following the direction in iOS Apprentice, was there a bug in the book
@fahim any thoughts?
here is the error in full
Fatal error: Unexpectedly found nil while unwrapping an Optional value: file /Users/isaacballas/Library/CloudStorage/iCloud Drive/Desktop/LocationTracker/LocationTracker/AppDelegate.swift, line 30
Without seeing your project, I can’t tell you for sure but it looks as if your root view controller might not be a tab view controller. Please compare your project against the final project for the chapter (specifically the storyboard) and see if both are set up the same way. Hopefully, that lets you figure out what is going on …
When I set up the project I set it up as a single page project, then implemented the tab bar on the storyboard… was that my mistake? can I fix it? how would I make the tab bar controller the root?
My suggestion would be to check in the storyboard and make sure that the arrow indicating rootVC (initial VC) is attached to a Tab Bar VC. It’s likely that you either don’t have the initial VC declared or that it’s pointing to a non-Tab Bar VC. Hence, the crash is happening either because there is no rootViewController or it can’t take the rootViewController and cast it as a UITabBarController.
I just checked, it is connected to tab bar, here is a screenshot, I have no clue why this is happening
Two other suggestions then.
-
Try to to do a clean of the app: hold down option, go to clean build folder. Then, go to Xcode preferences and clear the derived data. (xcode9 - How can I delete derived data in Xcode 9? - Stack Overflow)
-
Replace the one line of code that has three ! and turn it into three separate lines of code. This will at least allow you to figure out which thing is causing Xcode to crash.
Remove:
let tabBarController = window!.rootViewController as ! UITabBarController
replace:
let window = self.window!
let rootVC = window.rootViewController!
let tabBarController = rootVC as ! UITabBarController
any solution to the above question ?
@filly Do you still have issues with this?
I encountered this problem as well. Is there any solutions to this problem? my situation is completely the same as @isaacballas2.
I might have found a solution in Matt Neuburg’s book “Programming iOS 13” and on Andre Bancroft’s page. He writes that as of iOS 13 the app is launched with window scene support, which alters the order of assignments and, most importantly, the call to (_:didFinishLaunchingWithOptions:)
. I’ll quote here:
“Exactly how UIApplicationMain
proceeds depends on what it discovers as it gets going. New in iOS 13, your app can use scenes and scene-related classes and protocols (UISceneSession, UIScene, UIWindowScene, UIWindowSceneDelegate).”
As far as I understand the author and the steps he outlines in the launching process, in iOS 12 and older launching used to proceed as follows:
-
UIApplicationMain
looks to see whether your app uses a main storyboard; if so, it instantiates the storyboard’s first view controller (that would be yourUITabBarController
I presume). -
UIApplicationMain
assigns the window (of typeUIWindow
) to the app delegate’swindow
property. -
It then goes on to assign the view controller instantiated in step 1 as the window’s root view controller (that is the one your problematic line of code refers to), which retains it in memory.
-
It calls
(_:didFinishLaunchingWithOptions:)
This would be all well and good for your code, as the root view controller already exists when (_:didFinishLaunchingWithOptions:)
is called. However, in iOS 13 the order changes to the following:
-
After creating the application instance and assigning the app delegate class to its delegate property (I omitted that very first step above),
UIApplicationMain
immediately calls(_:didFinishLaunchingWithOptions:)
. This is problematic for your code because, at this point, not even a window exists yet and thus your force unwrap crashes the app. -
UIApplicationMain
goes on to create a UISceneSession, UIWindowScene and an instance of the window scene’s delegate. -
After that it checks if your app uses a storyboard and initializes the usual launching process (creating the window, assigning the first view controller’s view as its root view etc.)
-
Lastly, it calls
(_:willConnectTo:options:)
in theSceneDelegate
class.
Long story short, your code refers to something that does not exist at this point of time in the launching process. The fix would be to move your code over to the SceneDelegate
’s (_:willConnectTo:options:)
method, which is called at the same point in time when (_:didFinishLaunchingWithOptions:)
used to be called. Hope that helps.
@danielmey Thank you for sharing your solution - much appreciated! :]
Moving: listenForFatalCoreDataNotifications()
from: AppDelegate: didFinishLaunchingWithOptions
to: SceneDelegate: _:willConnectTo:options:
worked for me.
Thank you for that good writeup.