4

So the the problem is that when someone touches the back button on the UINavigationControler, I would like to run some code to update the datasource.

The problem is that i cant seem to find the right delegate to do it. only these are available on the nav controller delegate, and i want the 'didfinishshowing' type method.

– navigationController:willShowViewController:animated:  optional method  
– navigationController:didShowViewController:animated:  optional method  

The next best place i thought was the nav bar but when i try that.

Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Cannot manually set the delegate on a UINavigationBar managed by a controller

This makes sense retrospectively, as you don't want some hacker messing around with the internals of the nav controller and stopping it from working.

This must is a common problem, and i have missed something simple.

Bluephlame
  • 3,901
  • 4
  • 35
  • 51
  • Not that this is a solution, but I noticed that if the UINavigationController is instantiated from a storyboard you don't get the NSInternalInconsistencyException. – hyperspasm May 03 '16 at 20:29
  • 1
    You could also make the UINavigationController have a custom UINavigationBar subclass, eg. `[[UINavigationController alloc] initWithNavigationBarClass:[MyNavigationBar class] toolbarClass:nil]` and then override `- (UINavigationItem *)popNavigationItemAnimated:(BOOL)animated` in the UINavigationBar subclass. – hyperspasm May 03 '16 at 20:32

2 Answers2

10

Just so we're clear: view A is the starting point. User taps something and you slide right to view B. User taps the back button and you're going from B back to A and you want to do something as a result of the 'back' action.

There are three ways to do it (and on neither do you have to go near the navigationController -- these apply to the underlying viewControllers themselves):

  • As dmercredi suggests override viewWillAppear on view controller A so when you're heading back to it, it refreshes itself. Problem is that viewWillAppear is also called when A is called the very first time. So you'll have to set some sort of flag to distinguish between the first viewWillAppear and any subsequent ones when returning from B.

  • Override viewWillDisappear on view controller B and do your refreshing there. This will only get called when B is about to go away. If there's something on B that goes one level deeper or brings up a modal dialog on top, viewWillDisappear is going to get called so again you'll have to distinguish between the coming and the going.

  • Decouple the various views and use the delegate pattern. View controller A sets itself as a delegate of B and when B updates something it invokes the delegate method, so A is notified of the change and can update whatever it needs to. You can invoke the delegate method any time the user makes a change inside B or override viewWillDisappear and just do it one time on the way out.

Ramin
  • 13,343
  • 3
  • 33
  • 35
5

Add your refresh code to the viewWillAppear:(BOOL)animated method on the view controller that is about to be displayed. In your case, that is the view controller that's already on the navigation stack.

dmercredi
  • 2,112
  • 11
  • 10