How to dismiss a view when leaving it with tab bar controller - ios

I use a tab bar controller to go from VC1 to VC2. Doing so, VC1 stays in memory. I manage data with VC2 and when I go back to VC1 (with tab bar controller), I reload VC1 with a function in viewWillAppearit works fine, but the previous version of VC1 is still visible during animation reloaded.
I have to dismiss the VC1 (from the memory) before the animation or reload process begins.
I have tried, in viewWillAppear, and viewDidDisappear of VC1 these commands without success.
self.dismiss(animated: true, completion: nil)
self.presentedViewController?.dismiss(animated: true, completion: nil)
My guess is that the best approach is to dismiss VC1 when moving to VC2, but didn't find the way yet.
Thanks for your help.

My suggestion, use NotificationCenter to add observer in VC1 and trigger from VC2 if some event happen.
Adding observer.
NotificationCenter.default.addObserver(forName: Notification.Name(rawValue: "updateVC1"),
object:nil, queue:nil) {
notification in
// do something
}
Trigger the observer from VC2
NotificationCenter.default.post(name: Notification.Name(rawValue: "updateVC1"), object: nil)

Related

Dismissing View Controller in Modally Segue

I am creating an app that opens with ViewController1, then a button opens another view contoller (ViewController2) with a modally segue. Then ViewController2 has a button that opens another view controller (ViewController3) using another modally segue. Both 2 and 3 view contollers have a dismiss button that dismisses the view controller.
The problem is that whenever ViewController3 uses the dismiss button, it dismisses to ViewController 2 when I want it to dismiss to ViewController1. I've tried using the dismiss action to dismiss ViewController2 one the button is pressed, but then the segue doesn't get committed.
This may be confusing so please ask questions if you need help understanding. Thanks so much in advace!
(I am using Swift 3 and Xcode 8)
Two options off the top of my head:
1. Use NotificationCenter and Send a dismiss notification that ViewController2 is listening for
2. Set a parentViewController reference on ViewController3, and then call dismiss on the parent after dismissing itself.
This happen because all the 3 viewcontroller are in stack,whenever u dismiss the viewcontroller in top it moves to the one below it.
To navigate to viewcontroller1 use:-
if let viewcontroller1 = navigationController?.viewControllers[0]{
_ = navigationController?.popToViewController(viewcontroller1, animated: true)
}
it's simple!
//*** in ViewController2
NotificationCenter.default.addObserver(self, selector: #selector(ViewController.onCloseViewController2), name: NSNotification.Name(rawValue: "closeViewController2"), object: nil)
func onCloseViewController2() {
//this function is called from notification (sent by vc3)
self.navigationController?.dismiss(animated: true, completion: nil);
}
#IBAction func closeView2FromButton() {
//Directly close modal
self.onCloseViewController2();
}
//*** in ViewController3 (tap button)
#IBAction func closeView3FromButton() {
//dismiss vc3 and send a notification to vc2
self.navigationController?.dismiss(animated: true, completion: {
NotificationCenter.default.post(name: NSNotification.Name(rawValue: "closeViewController2"), object: nil);
});
}
Remember to later remove the observers when you do not need them in your code ;)

How to correctly close modal presented controller

I am opening a navigationController using either directly navigation segue in storyboard or called segue from code, but still created on storyboard.
Example:
self.performSegue(withIdentifier: "addNew", sender: nil)
Which then with modal transition opens a navigationController. NC then has a few view controllers on which all have close button on them and when I click on it it closes NC using:
self.navigationController?.dismiss(animated: true, completion: nil)
But afterwards when I switch between different ViewControllers on TabbarController or open some other view with push view I get:
Unbalanced calls to begin/end appearance transitions for
And also viewWillAppear on opened view isn't called. So can anyone tell me if I'm closing the NC correctly or is there some other way to prevent the error.
EDIT1:
changed the closing call from
controller.navigationController?.dismiss(animated: true, completion: nil)
to self.navigationController?.dismiss(animated: true, completion: nil) just to make the question easier.
Also tired:
self.dismiss(animated: true, completion:nil)
EDIT2:
Is it maybe bad to open a NC from VC that is on NC that is on UITabbarController or is just simply already bad to have NavigationControllers as tabs on TabbarController?
You may need to close the controller from that controller's side:
// place this to the target controller, which handles you that modal view
self.dismiss(animated: true) {
//completion:
}
or
self.dismiss(animated: true, completion:nil)

Pass data to VC that is not the previous VC

When I go from VC1 to VC2, if VC2 gets dismissed, I could easily pass data back to VC1 by setting protocal in VC2 and have VC1 conform to it. I want to do something similar, however, with the following difference
When I go from VC1-> NavVC->VC2-> VC3. When VC3 gets dismissed, VC1 is shown. I want to be able to pass data back to VC1 and initiate some function in VC1. For example, I have an image to upload in VC3. As soon as VC3 gets dismissed, I am hoping to have a function in VC1 such as the following function where the image was the data from VC3
func uploadInitiate(image: UIImage) {}
Relationship of the three VC
VC1 is normal VC. It presents VC2 via
let navController = UINavigationController.init(rootViewController: VC2)
self.navigationController?.presentViewController(navController, animated: true, completion: nil)
VC2 is a custom FusumaCamera photo picker from cocoapods.
Once image is selected, I go to VC3 with the selected Image via
self.navigationController!.pushViewController(postVC, animated: true)
At VC3, I allow the user to interact with the image and make comments and press a button to upload to the server. I thought it would be nice to dismiss the VC straight away after button press and allow VC1 to initiate the upload with the data the came from VC3 (That way I can have a progress bar under navigation bar or display any warnings there)
You have multiple patterns that you can apply in similar situations. i will go with the delegation (recomended) example. Imagine you have VC1->
that presents modally a UINavigationController as a root controller and from there VC2 pushes VC3 to the stack. You have to define multiple protocols that will be called on the way you dismiss the VC3
protocol DismissVCDelegate : class {
func dismissViewAndStartUpload(shouldUpload: Bool)
}
Then store the property:
weak var delegate: DismissVCDelegate!
Set the delegate when to the VC3 when you push it from VC2 and conform the the protocol you defined in VC2.
Apply the same pattern all the way back to VC1 where you have passed multiple times the protocol back and you can start you upload task and you should dismiss the modally presented navigation controller like that:
func dismissViewAndStartUpload(shouldUpload: Bool) {
self.presentedViewController.dismissViewControllerAnimated(true, completion: nil)}

Remove current ViewController after instantiate and presented the next VC

In iOS project, XCode, I have two VCs, VC1 and VC2. What I want to do is in VC1, have a button to go to VC2 using
let VC2 = self.storyboard?.instantiateViewControllerWithIdentifier("VC2") as! VC2
self.presentViewController(loginVC, animated: true)
After VC2 appears, I will never need to go back to VC1 so I want to remove it completely as VC1 has some downloading function that may still run in background. So I want to remove VC1. I have tried the following:
let VC2 = self.storyboard?.instantiateViewControllerWithIdentifier("VC2") as! VC2
self.presentViewController(loginVC, animated: true) {
self.removeFromParentViewController()
}
However, that does not seem to do the job as I still see the background download in progress. Is there a simple way of doing it? I do not really want to include navigation controller in this case.

How to properly dismiss the presented ViewController and go back to the parent ViewController?

I'm facing an issue that I will describe and have found some similar questions, but I don't believe pertains to my issue.
I have a UITabBarController with 2 tabs for VC1 and VC2. VC1 segues to VC4. VC2 segues to VC3 and VC3 segues to VC4. VC4 contains an MPMoviePlayerViewController instance, as depicted below:
- - - - - -> VC1 \
TAB BAR VC / - - -> VC4
\ /
-> VC2 -> VC3 -> /
I have a Notification that listens to when the Video finishes, and dismiss VC4, and go back to whichever parent VC presented VC4, i.e. if VC1 presented VC4, then upon dismissal of VC4, should go back to VC1. Likewise, if VC3 presented VC4, then upon dismissal of VC4, should go back to VC3.
In VC4:
override func viewDidLoad()
{
NSNotificationCenter.defaultCenter().addObserver(
self,
selector: "moviePlayerPlayBackDidFinish:",
name: MPMoviePlayerPlaybackDidFinishNotification,
object: player?.moviePlayer)
}
func moviePlayerPlayBackDidFinish(notification: NSNotification)
{
NSNotificationCenter.defaultCenter().removeObserver(
self,
name: MPMoviePlayerPlaybackDidFinishNotification,
object: notification.object
)
player!.view.removeFromSuperview()
self.presentedViewController?.dismissViewControllerAnimated(true, completion: nil)
}
I don't think I'm using the code properly because self.presentedViewController?.dismissViewControllerAnimated(true, completion: nil) stays at VC4.
I found some similar questions:
How to dismiss the current ViewController and go to another View in Swift
How to dismiss VIewController iOS Swift
modal View controllers - how to display and dismiss
However, the sequence segues are different, therefore I can't follow the suggestions.
How can I achieve this? Thanks
UPDATE:
The following code in moviePlayerPlayBackDidFinish properly dismisses VC4 and back to parent VC1 if going from VC1 -> VC4:
self.dismissViewControllerAnimated(true, completion: nil);
However, VC4 does not dismiss when going from VC3 -> VC4.
Finally solved my issue by adding the additional code in moviePlayerPlayBackDidFinish:
self.navigationController?.popViewControllerAnimated(true)
After much research, I found the solution from here: dismissViewControllerAnimated() does not dismiss view controller

Resources