Swift - self.navigationController becomes nil after navigating
I am experiencing a very strange error in my application, between two views, self.navigationController
it becomesnil
I have multiple view controllers: MainViewController
, SecondViewController
PastSessionsViewController
, JournalViewController
. I use it JournalViewController
for two purposes, to save a new record in CoreData or edit an older one. The details are irrelevant to this error.
The error occurs when I try to pop JournalViewController
from the stack and return to MainViewController
, but only when JournalViewController
in edit mode, not when it "saves the new write mode"
Any idea 1) why this is happening and 2) how to properly access it so that I can return to PastSessionsViewController
when returning from JournalViewController
in edit mode?
Here's some code to make things specific.
In AppDelegate.swift
(inside didFinishLaunchingWithOptions
):
navController = UINavigationController()
navController!.navigationBarHidden = true
var viewController = MainViewController()
navController!.pushViewController(viewController, animated: false)
window = UIWindow(frame: UIScreen.mainScreen().bounds)
window?.backgroundColor = UIColor.whiteColor()
window?.rootViewController = navController
window?.makeKeyAndVisible()
In MainViewController
:
func goToPastSessions(sender: UIButton) {
let pastSessionsVC = PastSessionsViewController()
self.navigationController?.pushViewController(pastSessionsVC, animated: true)
}
func goToWriteJournalEntry(sender: UIButton) {
let journalVC = JournalViewController(label: "Record your thoughts")
self.navigationController?.pushViewController(journalVC, animated: true)
}
In PastSessionsViewController
:
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
let editJournalVC = JournalViewController(label: "Edit your thoughts")
let indexPath = tableView.indexPathForSelectedRow()
let location = indexPath?.row
let currentCell = tableView.cellForRowAtIndexPath(indexPath!) as! EntryCell
if let objects = pastSessionsDataSource.coreDataReturn {
if let location = location {
editJournalVC.journalEntryCoreDataLocation = location
editJournalVC.editEntry = true
editJournalVC.journalEntryToEdit = objects[location].journalEntry
}
}
self.navigationController?.presentViewController(editJournalVC, animated: true, completion: nil)
}
Finally, in JournalViewController
:
func doneJournalEntry(sender: UIButton) {
journalEntryTextArea?.resignFirstResponder()
var entry = journalEntryTextArea?.text
if let entry = entry {
let appDelegate = (UIApplication.sharedApplication().delegate as! AppDelegate)
let managedObjectContext = appDelegate.managedObjectContext!
let request = NSFetchRequest(entityName: "Session")
var error: NSError?
// new entry
if journalEntryText == "Record your thoughts" {
let result = managedObjectContext.executeFetchRequest(request, error: &error)
if let objects = result as? [Session] {
if let lastTime = objects.last {
lastTime.journalEntry = entry
}
}
} else {
// existing entry
let sortDescriptor = NSSortDescriptor(key: "date", ascending: false)
request.sortDescriptors = [sortDescriptor]
let result = managedObjectContext.executeFetchRequest(request, error: &error)
if let objects = result as? [Session] {
var location = journalEntryCoreDataLocation
var object = objects[location!]
object.journalEntry = entry
}
}
if !managedObjectContext.save(&error) {
println("save failed: \(error?.localizedDescription)")
}
}
// in "edit" mode, self.navigationController is `nil` and this fails
// in "record a new entry" mode, it not nil and works fine
self.navigationController?.popViewControllerAnimated(true)
}
func cancelEntryOrEditAndReturn(sender: UIButton) {
self.journalEntryTextArea?.resignFirstResponder()
// in "edit" mode, self.navigationController is `nil` and this fails
// in "record a new entry" mode, it not nil and works fine
self.navigationController?.popViewControllerAnimated(true)
}
Thanks for watching
source to share
You have to click editJournalVC instead of the view if you want it to be on the same navigation stack. Because when you present a controller, it is no longer on the same navigation stack. Also, if you present it, you must reject it not pop. Therefore, if you want to expose a controller, you must use
self.dismissViewControllerAnimated(true, completion: nil)
instead
self.navigationController?.popViewControllerAnimated(true)
source to share