iOS - How to not present model view if it is presenting? - ios

I have a floating button to present a model view. I call presentViewController in AppDelegate
UIApplication.sharedApplication().keyWindow?.rootViewController!.getTopViewController().presentViewController(myViewController, animated: false, completion: nil)
When myViewController is presenting, I click my floating button again and my application will call myViewController one more time. So how to not present if it presenting?

What you can do is add a check on your button to check whether the present controller is presenting something which can be done like this
let controller = UIApplication.sharedApplication().keyWindow?.rootViewController!.getTopViewController()
if controller.presentedViewController == nil {
controller.presentViewController(myViewController, animated: false, completion: nil)
}

Related

Segueing to New View Controller while Dismissing previous without navigation controller: swift

Hello I am pretty annoyed with this:
Originally, I had many segues in my storyboard. Each button at bottom of tool bar would segue to various view controllers. As you can imagine, that is a lot of segues for 6 different items on toolbar. After segueing, each action would call self.dismiss and everything would be ok.
Recently, I wanted to clean up the storyboard.
I created the function:
extension UIViewController {
func segue(StoryboardID: String) {
let popOverVC = UIStoryboard(name: "Main", bundle:
nil).instantiateViewController(identifier: StoryboardID)
popOverVC.modalPresentationStyle = UIModalPresentationStyle.fullScreen
popOverVC.modalTransitionStyle = .crossDissolve
self.dismiss(animated: false, completion: nil)
print("dismissed")
self.present(popOverVC, animated: false, completion: nil)
print("presented")
}
}
What I am seeing is that the dismiss dismisses the new view controller from appearing. It essentially goes back to my first view controller presented upon launch. I want to dismiss all view controllers so that I don't keep piling up my views.
Thanks
The problem is that you present your popOverVC from a view controller that is being dismissed, so your popOverVC will never be shown as its parent is being dismissed.
Not sure how your architecture is exactly but you would either need to use the delegate pattern to tell the parent when to segue, for example:
self.dismiss(animated: true) {
self.delegate?.didDismiss(viewController: self)
}
Or to use some trick to get the top most view controller to present your popOverVC after the current view has been dismissed, ex:
self.dismiss(animated: true) {
var topController: UIViewController = UIApplication.shared.windows.filter{$0.isKeyWindow}.first!.rootViewController!
while (topController.presentedViewController != nil) {
topController = topController.presentedViewController!
}
topController.present(popOverVC, animated: true)
}
But I agree with #Paulw11, a UITabBarController seem like a much better option for what you're trying to do.

How to dismiss a viewController to rootViewController without showing any VCs in between dismiss process?

Let say I have the following VCs:
RootVC --> VC A --> VC B
I'm using present method to present view controller from RootVC to VC A then to VC B. Now I'm on VC B and I want to dismiss from VC B back to RootVC using
self.view.window!.rootViewController?.dismiss(animated: true, completion: nil)
it works but I still see VC A shows up during the dismiss process. Then, I try this method
self.presentationController?.presentedViewController.dismiss(animated: true, completion: nil)
It also works to dismiss back to root VC but I still see VC A in process.
My question is is there a way to not show VC A during the dismiss process? I already try animated: false but still get the same result. Thanks!
You need to make the change in the modalPresentationStyle to the .custom. The custom will allow you to view the presentingViewController view when the current visible controller's view is transparent.
Now when you want to go back to root view on the current presenting stack you need to call the method dismissToRootViewController(animated: completion:).
In the implementation of this method will allow all intermediate presenting view controller view to be transparent which will give you dismiss animation from VC c to RootVC.
extension UIViewController {
func dismissToRootViewController(animated: Bool, completion: (() -> Swift.Void)? = nil) {
var viewController = self.presentingViewController
while viewController?.presentingViewController != nil {
viewController?.view.alpha = 0.0
viewController = viewController?.presentingViewController
}
self.dismiss(animated: true) {
viewController?.dismiss(animated: false, completion: completion)
}
}
}
You can try to use this:
navigationController?.popToRootViewController(animated: false)

Swift : present a ViewController while alert is shown

I have a problem with present UIViewController Modaly by above code
self.presentViewController(view, animated: true, completion: nil);
it doesn't work when another view present modaly such as UIAlert,its triggered by a socket packet in background and user may is performing another work and may another modal view already presented when the trigger happens.
You can not present two view controllers at the same time from the same source controller. Instead, try presenting the second view controller from the first one that was presented.
if let presented = self.presentedViewController {
presented.present(vcToPresent, animated: true, completion: nil)
}
else {
self.present(vcToPresent, animated: true, completion: nil)
}

View over view breaks hierarchical

I'm using MZFormSheetPresentationController to show as "pop-up" a ViewController2 (embedded in a Navigation controller as suggested) over a ViewController1.
My ViewController1 has a searchbar, a UISegmentedControl and a tableview:
When user clicks on the searchbar bookmark button, pop-up is shown.
I'd like to close the pop-up when user clicks on the done button and it works great using self.dismissViewControllerAnimated(true, completion: nil) method but I'm looking for more. I'd like to present again ViewController1 so tableView will reload data.
I tried with:
self.dismissViewControllerAnimated(true, completion: nil)
print("Dismissed")
//goToTickets
let next = self.storyboard?.instantiateViewControllerWithIdentifier("myTabBar") as! UITabBarController
self.presentViewController(next, animated: true, completion: nil)
but I get this error:
Warning: Attempt to present on whose view is not in the window hierarchy!
Pop-up disappears but I can't present ViewController.
How can I do?
Thanks in advance.
Edit
This is my ViewController2 with identifier "navigationFilter"
and my tabBar:
When you are in the middle of dismissing you are trying to present next ViewController, you have to wait for completion handler and then present next view controller like this:
self.dismissViewControllerAnimated(true, completion: {
let next = self.storyboard?.instantiateViewControllerWithIdentifier("myTabBar") as! UITabBarController
self.presentViewController(next, animated: true, completion: nil)
})

Dismissing a UINavigationController and Presenting another UINavigationController

I have a two view controllers, ViewControllerA and ViewControllerB, embedded in a UINavigationController. ViewControllerA has a UICollectionView that displays images.
When the camera icon located at index 0 and the UICollectionViewCell is selected, it should dismiss ViewControllerA and display ViewControllerB. And also, there is a ViewController that presents ViewControllerA modally
This is what I've done, but it only dismiss ViewControllerA and nothing happens
let controller = self.storyboard?.instantiateViewControllerWithIdentifier("cameraViewController") as! UINavigationController
self.dismissViewControllerAnimated(true, completion: { () -> Void in
self.presentingViewController?.presentViewController(controller, animated: true, completion: nil)
})
When view controller is dismissed, my guess is self is already deallocated so self.presentingViewController? becomes nil too. I would create a strong reference to presenting view controller right before dismissing action takes place:
let presentingViewController = self.presentingViewController
self.dismissViewControllerAnimated(true) { completed in
if completed {
presentingViewController?.presentViewController(controller, animated: true, completion: nil)
}
}
Also, make sure self.presentingViewController is not nil in the first place.
The reason nothing is happening is because self.presentingViewController? is nil.
If instead, you were using self.presentingViewController!, there would be an error stating Unexpectedly found nil while unwrapping optional value, which should always be avoided.
You are correct in using self.presentingViewController? instead of self.presentingViewController!, as it is much safer, but in order to fix this, you must make sure that self.presentingViewController? is not nil.
let presenting = self.presentingViewController
self.dismissViewControllerAnimated(true, completion: {() -> Void in
presenting?.presentViewController(controller, animated: true, completion: nil)
})

Resources