Swift 3 - How to add navigation controllers buttons (as Back) after renewing - refresh and reload my viewcontroller - swift

I am trying to refresh my viewcontroller (reload it ) using UIApplication.shared.keyWindow?.rootViewController as shown below in code, it works however when reloaded the novaigation controller is not there, I mean there a back button that can go to previous view controller it does not appear when I did that - any help
#IBAction func Save(_ sender: AnyObject) {
UIApplication.shared.keyWindow?.rootViewController = storyboard!.instantiateViewController(withIdentifier: "UploadPhotoviewcontroller")
}

Default back button, appearance and work in current navigationController navigation stack. If you change rootViewController, this action will destroy you current navigation stack and all previous controllers. And you cant go back.
Change the rootViewController be bad practic. I think you have a problems with the architecture

#jon when I try to comment it did not and I can not reply to your question as comment - I do not know why
Exactly that is the reason

I found the answer:
To deselect the picked image in elcimagepickercontroller use below code:
imagePicker.popToRootViewController(animated: true)
self.dismiss(animated: true, completion: nil)

Related

Black screen with viewDidLoad after if else statement

I want my app to check at start conditionaly if a variable is correct or not. Based on that it should either go to an intro screen (where he can select a variable in my case select a team) or it should start the main view. After searching i found this code and edited it. But there still seems to be problems. First of all I dont have two identifier. The Intro has one but not the main view. My main View is called WeatherViewController and the Intro screen is called FirstScreenViewController. I also added a picture of my Main.storyboard.
I also googled a lot about conditional UINavigationController but I can only understand with a video and did not found a video about it.
I tried to use the code from here.
var id = hello ? "goToIntro" : "???"
self.window = UIWindow(frame: UIScreen.main.bounds)
let mainStoryboard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let WeatherViewController: UIViewController = mainStoryboard.FirstScreenViewController(withIdentifier: WVC has no identifier??) as UIViewController
self.window?.rootViewController = WeatherViewController
self.window?.makeKeyAndVisible()
if hello {
self.performSegue(withIdentifier: "goToIntro", sender: self)
} else {
/here nothing should happen. It should open the Main View
self.performSegue(withIdentifier: "???", sender: self)
}
Note: This answer was referring to the original question (before any edits) that was attempting a segue inside loadView().
You're supposed to manually create your controller's view in loadView. You're currently doing nothing, hence the black screen. Furthermore, if you are using a Storyboard or a xib for managing this controller you shouldn't be overriding loadView at all.
Having said that it might be a better idea to move this branching logic a step back, to "something" (a container controller like a UINavigationController or a custom one, or even directly setting the root controller of your window if it makes sense) that will present (or set) A or B based on some condition and thus avoid to load this controller altogether (have in mind that in your code, the controller is initialized, it will be part of the hierarchy and all the lifecycle methods will be called even if you segued directly to another one)
Finally, if you decide for some reason to override loadView you don't have to call viewDidLoad yourself, the system will call this method.

Dismiss completly a view controller in middle

I've been looking for days. Here's the problem:
I have a Home view controller. When it receives a notification, it presents a NotiViewController, called noti1, by
`home.present(noti1, animated: true, completion: nil)`.
After 15sec, another notification comes, I get the top view controller topVC, present another NotiViewController, called noti2, by
`topVC.present(noti2, animated: true, completion: nil)`.
Each notiVC has an timer which waits for 30sec to dismiss itself. Now I have Home -> noti1 -> noti2.
After 15sec, noti1 runs out of time and has to be dismissed. How can I dismiss it without interupting noti2 which is being presenting?
I tried
`orderVC.beginAppearanceTransition(false, animated: false)
orderVC.willMove(toParent: nil)
orderVC.view.removeFromSuperview()
orderVC.removeFromParent()
orderVC.endAppearanceTransition()`
These code does remove the view from screen, but it leaves a UITransitionView behind, which blocks user actions.
This image is took after noti2 is removed from superview etc, so there are 2 UITransitionViews is presenting, blocking user actions.
Any idea? Thanks a lot.
Found a way. I'm not sure if I'm correct or wrong, but here is my thought: View controller must be dismissed the way it's presented before. For example if you use present(viewController, animated, completion) to present, you should use dismiss(animated, completion) to dismiss. The problem, in my case, is if you dismiss a view controller, all child view controllers will be gone too.
The way I resolved my issue is using another way to "show" the target view controller:
parentVC.view.addSubview(childVC.view)
parentVC.addChild(childVC)
childVC.didMove(toParent: parentVC)
After adding some view controllers, I got a tree parentVC -> child1 -> child2 -> child3... If I want to dismiss child2, the code in my question worked:
child2.willMove(toParent: nil)
child2.view.removeFromSuperview()
child2.removeFromParent()
There is no UITransitionView blocking user actions, but it got no animation. For my this is good enough.

Clear stack of ViewControllers when Exit and Re-login

i've an app in swift 5, where i want to my user can logout, going to a login screen, so i created a menu with option "Logout". the option is working, but, when i logout and login again, instead of my "segue" leave to the main screen, leaves back to the option menu, where i was before. So, I need to, when I logout, clear my previous stack, to i don't go back to my Menu, previosly openned, when i re-login.
I tried to use dismiss method, uwind segue and popToRootViewController, but, or not worked, or they had a delay, and poped up my login screen, instead of my option menu.
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
//self.navigationController?.popToRootViewController(animated: false)
}
Set the rootViewController of the main window that lives inside the app delegate:
(UIApplication.shared.delegate as! AppDelegate).window!.rootViewController = vc

Come back to the tabBarController, swift

Currently on my viewController : Upload, my button send the data to my database only if all the information are filled out, and I come back to the preview view (table View) with :
self.navigationController?.popViewControllerAnimated(true)
I would like, if it is possible, to come back to my main view on the tabBarController. I tried many things, like directly on the storyboard with Present modally segue to "TabBar controller", but I come back to the TabBar without sending my data to the database and without checking in the information are filled out..
How can I do it?
Thanks!
UITabBarController has a property selectedIndex with which you can switch the selected tab. So on completion after dismissing the UploadViewController you can run:
self.tabBarController?.selectedIndex = 0 // Index to select
It would probably be best to create a delegate for your UploadViewController to fire a function to do all the work in your previewVC on API call completion.
(Super late response...in case someone has similar questions, presumably in later version of Swift, such as mine which is Swift 5, iOS 13.2). Steps:
Be sure to set an id for your UITabBarController storyboard, e.g. "TabBarViewController"
Next, add the following to an action that has already been connected to a button:
let ID_TABBAR = "TabBarViewCOntroller"
#IBAction func returnToTabbar(_ sender: Any) {
let tabBarController = self.storyboard?.instantiateViewController(identifier:ID_TABBAR) as! UITabBarController
self.navigationController?.pushViewController(tabBarController, animated:true)
}
Referenced from one of the responses from this post.
Update: In case your Tab Bar View Controller also happens to be the root view controller, the two lines of the code in the returnToTabbar method above can be:
self.dismiss(animated:true, completion:nil);
self.navigationController?.popViewController(animated:true);
(ref.: See answer here, for Swift4 but works just fine in Swift5)

UINavigationController - Run Code Before Popping View Controller

I have a stack of UIViewController subclasses. Each modifies a NSManagedObject model. Many of them also present their own modal view controllers.
I need to save changes to the NSManagedObjectContext when a user either 'pops' the view controller or pushes the next view controller.
Currently, I'm hiding the default back button and setting my own UIBarButtonItem with a target of self and a custom action.
This works okay, but ideally, I want to use the default back button and run code before the pop. Is there a way I can run my own code before the pop?
(I'd prefer not to put code into viewWillDisappear as persisting to disk can be expensive and this method can also be triggered by modals being displayed by view controller.) Can it be done?
You can do it in viewDidDisappear, after checking that self is either 1) the second last element in self.navigationController.viewControllers (the case where the next VC just got pushed) or 2) self.navigationController is nil (the self VC just got popped).
Yes.. Navigation controller has a delegate which indicates when a view controller popped or pushed.. You can use that to do your task...
Add following method in your code:
- (void) viewWillDisappear:(BOOL)animated{
//your code here
}
I use viewWillDissappear to make any changes persistant.
If required i Use viewWillAppear to recoginze any changes (reload the data) that may have taken place while other puhed view controlers did their work.
For pop check isMovingFromParent in viewWillDisappear
func viewWillDisappear(_ animation:Bool){
super.viewWillDisappear(animation);
if isMovingFromParent {
// your code here
}
}