Reloading data when clicking back bar button of an UINavigationController - ios

I have an UINavigationController and it has an UITableViewController as its root controller. I reload the data for the table view in viewWillAppear. When I select an item in the table view it will push an new UIViewController with which the user could edit the data that will be shown in the table view, and then I clicked Back of the navigation, viewWillAppear of the UITableViewController was just not called and the data was not reloaded.
So in this case where could I reload the data for the table view?
Thanks.

The easiest way to do that is to use UINavigationControllerDelegate. There are two methods available:
func navigationController(navigationController: UINavigationController, willShowViewController viewController: UIViewController, animated animated: Bool)
func navigationController(navigationController: UINavigationController, didShowViewController viewController: UIViewController, animated animated: Bool)
In your UITableViewController(root) you should add UINavigationControllerDelegate and method navigationControllerWillShowViewController will be called when you are going back. Here's an example:
class RootTableViewController: UITableViewController, UINavigationControllerDelegate {
...
func navigationController(navigationController: UINavigationController, didShowViewController viewController: UIViewController, animated animated: Bool) {
//Will run
}
...
}

viewWillAppear is called when you hit the back button. Just put a log in there if you don't believe me! Most likely the table is not reloading the way you want it to because there is something wrong with the table datasource.

Related

NavigationController.topViewController is equal to viewController in navigationController delegate

I am implementing the navigationControllerDelegate func:
func navigationController(_ navigationController: UINavigationController, willShow viewController: UIViewController, animated: Bool) {
print("callin the Navigation Controller Delgate")
if viewController === self {
print("Calling the Navigation Controller delegate because is self and going to call tapButton")
//want to know who was previously on top of navigation.
}
}
I want to know here which was the viewController that is being removed form the stack since apple docs says that the
viewController
The view controller whose view and navigation item properties are being shown.
This means that this assumption is true:
viewController == navigationController.topViewController
or this one:
viewController == navigationController.visibleViewController
If not then one of this are the the viewControllers that is going to be removed.
It's not cleat for me since the func parameter name is willShow viewController, or is just a fancy name and the will show is the already shown.
So if not how from the delegate I may know which VC is being removed from the Navigation Stack.
It would have been nice if the delegate provided the viewController being removed, but I found it's just straight forward just to keep a reference.
weak var lastRemovedViewController: UIViewController? = nil
func navigationController(_ navigationController: UINavigationController, willShow viewController: UIViewController, animated: Bool) {
defer { lastRemovedViewController = viewController }
print("Navigation Removed \(lastRemovedViewController.debugDescription)")
}
yes is the answer, the viewController passed in the delegate func is the same as the topViewController, also is equal to navigationController.visibleViewController. so there is no way to know which was the removed viewController from the stack.

How to do 'prepareSegue' for back button?

I've got a pretty simple question. In my app, there are some screens that have a navigation bar, and some that don't have it. So, what I did was to flag this manually between screen in prepareForSegue: using this line self.navigationController?.setNavigationBarHidden(true/false, animated: false) . Now, how do I do it if I want to go back from a view controller with a navigation bar to a view controller that doesn't have it by clicking on the back button? I tried putting it in the prepareForSegue: of the child view controller but it doesn't work.
Thanks.
It depends how you are maintaining your flags for hiding/unhiding the navigation Bar but you can use UINavigationControllerDelegate for the same
#available(iOS 2.0, *)
optional public func navigationController(_ navigationController: UINavigationController, willShow viewController: UIViewController, animated: Bool)
#available(iOS 2.0, *)
optional public func navigationController(_ navigationController: UINavigationController, didShow viewController: UIViewController, animated: Bool)
Alternatively, you can try to put setNavigationBarHidden in viewWillAppear and viewWillDisappear for each viewController.
you can also use a better approach with unwind segue
override func didMoveToParentViewController(parent: UIViewController?) {
if (parent == nil) {
println("Back Button Pressed!")
}
}

How can I check if my NavigationController subclass has had VC's pushed & popped?

This Apple Doc looks promising, https://developer.apple.com/reference/uikit/uinavigationcontrollerdelegate?language=objc but they are not getting called.
I have a CustomNavigationController that inherits from UINavigationController. I need to know when a VC has been pushed or popped from my CustomNavC.
I can conform to UINavigationControllerDelegate, but this seems to be more for ViewControllers. Not for the CustomNavC to do a self.delegate = self.
How can this be achieved?
UPDATE: False alarm. Sorry all. I was testing on device and had OS_ACTIVITY_MODE disabled. The UINavigationControllerDelegate functions work just fine.
One option is to override the pushViewController and popViewController methods.
- (void)pushViewController:(UIViewController *)viewController animated:(BOOL)animated {
[super pushViewController:viewController animated:animated];
// Handle push as needed
}
There are several pop... methods you can override as well.
You may also wish to override the setViewControllers:animated: method which is called when the whole stack is replaced.
Overriding these methods leaves the delegate free to be used by other classes.
Maybe you can implement UINavigationControllerDelegate in your CustomNavigationController and add these functions:
func navigationController(_ navigationController: UINavigationController, willShow viewController: UIViewController, animated: Bool) {
}
func navigationController(_ navigationController: UINavigationController, didShow viewController: UIViewController, animated: Bool) {
}

UINavigationController transition delegate

I have implemented UINavigationControllerDelegate method:
public func navigationController(navigationController: UINavigationController, animationControllerForOperation operation: UINavigationControllerOperation, fromViewController fromVC: UIViewController, toViewController toVC: UIViewController) -> UIViewControllerAnimatedTransitioning? { }
because I had to set application state and only "event" that was able to capture Pop transition of my UINavigationController was this method. Everything is working properly but as far as that functionality is concerned, but now my swipe back action does not work (only pressing back button works).
At the end of this method I have returned nil because I had no idea what its doing but apparently it affects that swipe to back functionality.
Is there any default UIViewControllerAnimatedTransitioning that I can returned to have that swipe back functionality?
Thanks.
I switched to this delegate method:
public func navigationController(navigationController: UINavigationController, willShowViewController viewController: UIViewController, animated: Bool) {
if self.viewControllerCount - 1 == self.rootController.viewControllers.count {
// Pop action, do additional logic
}
}
and customized it so that I can know for sure if its pop action (tracking last number of view controllers.

Sending information to a view I'm returning to in Navigation Controller

I have an app that includes a UIView in two different views. I want these two UIViews to show the same custom drawings, and have one be editable and one not be editable. When I segue from one view controller to the next (from the vc with the non-editable view to the editable one), I see the back button in UINavigation controller. Now, after I edit the view, I want the changes to be reflected in the non-editable view. I want to do this by being notified when the back button is pressed. So far, what I've tried hasn't worked:
public class BlockingViewController: UIViewController, UINavigationControllerDelegate {
func navigationController(navigationController: UINavigationController, viewController: UIViewController, animated: Bool) {
print("In function")
}
}
I took the navigationController method signature from https://developer.apple.com/library/ios/documentation/UIKit/reference/UINavigationControllerDelegate_Protocol/index.html but I'm not sure what changes I made that made it not work. I took out the optional declaration because including it gave me an error message stating "optional can only be applied to protocol members." I thought this was a protocol member, but I guess not.
That function declaration is incorrect. It should look like this,
func navigationController(navigationController: UINavigationController, didShowViewController viewController: UIViewController, animated: Bool) {
println("In function")
}
(or willShowViewController, if that's the one you want)

Resources