Can one uitableviewcell segue 2 view? - swift

i wanted to ask, if i got one uitableviewcell, i need to do checking to meet the condition then only perform to different segue to different view, how to do it? Example like:
if subCat[indexPath.row] == ""{
performSegueWithIdentifier("A", sender: self)
}else{
performSegueWithIdentifier("B", sender: self)
}
How to do it? And how should i connect it with segue at the storyboard?

Even you can do by giving storyboard identifier "A" to viewController 1 and "B" to viewController 2 and push you controller if using navigation otherwise simply present the viewcontroller.
if subCat[indexPath.row] == "" {
let viewController1 = storyboard.instantiateViewControllerWithIdentifier("A") as! ViewController1
// if navigation controller used.
self.navigationController?.pushViewController(viewController1, animated: true)
// if navigation controller not used.
// self.presentViewController(viewController1, animated: true, completion: nil)
}else{
let viewController2 = storyboard.instantiateViewControllerWithIdentifier("B") as! ViewController2
// if navigation controller used.
self.navigationController?.pushViewController(viewController2, animated: true)
// if navigation controller not used.
// self.presentViewController(viewController2, animated: true, completion: nil)
}

Related

Present Next ViewController to Dismiss current ViewController Using Swift

My Scenario, I have three ViewControllers, those ViewControllers First, Second, Third. Here, First ViewController UIButton click to present model second ViewController and then Second ViewController UIButton click to present model Third ViewController. I need to Implement the Second ViewController button click to dismiss current ViewController after presenting Third ViewController because once I close Third ViewController I need to show First ViewController. How to Achieve this?
NOTE: I am having NavigationController for Third ViewController also I am using Storyboard.
Here's my code:
#IBAction func ClickThirdVC(_ sender: Any) {
if let VC_Third = self.storyboard?.instantiateViewController(withIdentifier: "thirdviewcontroller") as? ThirdvViewController {
weak var pvc = self.presentingViewController
VC_B.modalTransitionStyle = .crossDissolve
let navController = UINavigationController(rootViewController: VC_B)
self.dismiss(animated: true, completion: {
pvc?.present(navController, animated: true, completion: nil)
})
}
}
You can try to dismiss self after presenting the third UIViewController, in the completion handler of the present function .
secondVC?.present(navController, animated: true) {
self.dismiss(animated: false, completion: nil) //dismiss self after presenting the third.
}

How to dismiss a navigation controller?

I'm presenting a navigation controller (detailview) with showDetailViewController(). I want to dismiss it when a button is pressed. How can I dismiss this viewcontroller?
Code I've attempted:
//detailviewcontroller
#objc
func cancel(_ sender: Any) {
print("cancelPressed")
//self.navigationController?.popViewController(animated: true)
//self.navigationController?.dismiss(animated: true, completion: nil)
//self.dismiss(animated: true, completion: nil)
//splitViewController?.dismiss(animated: true, completion: nil)
//splitViewController?.navigationController?.popToRootViewController(animated: true)
//splitViewController?.navigationController?.popViewController(animated: true)
//splitViewController?.navigationController?.dismiss(animated: true, completion: nil)
//navigationController?.popViewController(animated: true)
//navigationController?.dismiss(animated: true, completion: nil)
//self.navigationController?.popToRootViewController(animated: true)
//self.navigationController?.viewControllers.remove(at: 1)
//self.navigationController?.viewControllers.remove(at: 0) - this one removes to blank view
//self.presentingViewController?.dismiss(animated: true, completion: nil)
}
I've tried multiple stackoverflow solutions:
Dismissing a navigation view controller
How to dismiss a view controller in a navigation controller, without dismissing the whole stack
ios swift - dismiss root view controller of navigation controller
Can't dismiss View Controller that's embedded in a Navigation Controller
How to dismiss a navigation controller presented from another navigation controller in iOS 10 and below?
Can't dismiss navigation controller in Swift
Can't dismiss navigation controller in Swift
Dismissing View Controller Doesn't Work While Using Navigation Controller
Dismiss current navigation controller when clicked tab bar
How to dismiss a certain view controller
How I'm presenting the detailviewcontroller:
//masterviewcontroller
// delegation for passing data between controllers
weak var passDelegate: PlaceSelectionDelegate?
func insertNewObject(_ sender: Any) {
if let detailViewController = passDelegate as? DetailViewController {
if let detailNavigationController = detailViewController.navigationController {
detailViewController.delegate = self
splitViewController?.showDetailViewController(detailNavigationController, sender: nil)
}
}
}
Expected results:
dismiss detail viewController on button press.
Actual results:
No dismiss.
Ok, I've been looking for a way of dealing with this showDetailViewController for a while now and although I'm not sure this answers your question, this is how I did it:
I have two controllers, let's call it FirstController and SecondController. They both inherit from UIViewController. When I click a certain navbar button in the FirstController, I use showDetailViewController to show SecondController as a sheet moving upwards, like the "calendars" button in the Calendar app.
In FirstController I implemented 2 functions: one to show the SecondController and one to dismiss it. I call the dismiss action from within the SecondController. It looks like this:
// FirstController
#objc func showSecondView() {
let vc = SecondController()
vc.delegate = self
let nav = UINavigationController(rootViewController:vc)
self.showDetailViewController(nav, sender: self)
}
func closeSecondView() {
self.dismiss(animated: true)
}
As you can see I wrapped my SecondController in a UINavigationController, so it shows the navbar with title and all. This is how the code looks like:
// SecondController
weak var delegate: FirstController!
override func viewDidLoad() {
super.viewDidLoad()
title = "Second"
navigationItem.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: .done, target: self, action: #selector(closeMe))
}
#objc func closeMe() {
delegate.closeSecondView()
}
Notice how I made a property for the FirstController and I use it to dismiss the SecondController. When I presented SecondController I assigned self as delegate, which means I can now call the closeSecondView method from within it.
I am not sure whether it works out of the box with split-view. The documentation seems to suggest that whenever you use it, if the screen is big enough, it behaves differently because UISplitViewController overrides it. It also says there that all view controllers have this method.
Take a look: https://developer.apple.com/documentation/uikit/uiviewcontroller/1621432-showdetailviewcontroller
Give it a go, I hope this helps.
This should work if you simply want to dismiss the navigation controller
navigationController?.dismiss(animated: true, completion: nil)

Swift: pass data to first child of NavigationController instantiate with storyboardID

I want to pass data to the first viewController which is embeded in navigationController.
To access this navigation controller it has a storyBoardID, I arrive at instantiate navigationController but I can not pass him data,
Here is my code:
extension UINavigationController {
func dismissAndPresentNavigationController(from storyboard: UIStoryboard?, identifier: String) {
guard let navigationController = storyboard?.instantiateViewController(withIdentifier: identifier) as? UINavigationController else { return }
print("OK")
if let nav = navigationController.navigationController?.viewControllers.first as? ChatBotViewController{
print("OK2")
}
self.dismiss(animated: false, completion: nil)
self.present(navigationController, animated: true, completion: nil)
}
}
The identifier that I put in parameter is the storyBoardID of the navigation controller.
How to transmit data to the first controller of navigationcontroller?
SOLUTION:
extension UINavigationController {
func dismissAndPresentNavigationController(from storyboard: UIStoryboard?, identifier: String, with fittoBottle: FittoBottle) {
guard let navigationController = storyboard?.instantiateViewController(withIdentifier: identifier) as? UINavigationController else { return }
if let nav = navigationController.viewControllers.first as? ChatBotViewController{
nav.fittoBottle = fittoBottle
}
self.dismiss(animated: false, completion: nil)
self.present(navigationController, animated: true, completion: nil)
}
After instantiating the navigation controller from the storyboard, you will be able to access the root view controller via navigationController.viewControllers.first.
guard let navigationController = storyboard?.instantiateViewController(withIdentifier: identifier) as? UINavigationController else { return }
if let chatBotViewController = navigationController.viewControllers.first as? ChatBotViewController {
chatBotViewController.fittoBottle = fittoBottle
}
self.dismiss(animated: false, completion: nil)
self.present(navigationController, animated: true, completion: nil)
To communicate between view controllers in an iOS app, the best way is using protocol (delegate) or Notification. In you case, extending an UINavigationController doesn't sound a good idea, because you shouldn't relay on extension methods to instance view controller and then passing any data to it, and as an extension method, it's not the responsibility for an UINavigationController to take care about ChatBotViewController or any other instanced controllers.
For my suggestion, in anywhere you want to show the ChatBotViewController, in your storyboard, create a presenting modal segue to the ChatBotViewController (which is embedded in an UINavigationController), and use performSegue(withIdentifier:sender:) to initiate the navigation controller, and override prepare(for:sender:) to set the data you want to pass in your ChatBotViewController.
Here's some codes for explaining:
import UIKit
struct FittoBottle {
}
class ChatBotViewController: UIViewController {
var fittoBottle = FittoBottle()
}
class ViewController: UIViewController {
func showChatController() {
/*
If there is any controller is presented by this view controller
or one of its ancestors in the view controller hierarchy,
we will dismiss it first.
*/
if presentedViewController != nil {
dismiss(animated: true) {
self.showChatController()
}
return
}
// Data that will be sent to the new controller
let fittoBottle = FittoBottle()
// ChatBotViewControllerSegue is the segue identifier set in your storyboard.
performSegue(withIdentifier: "ChatBotViewControllerSegue", sender: fittoBottle)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
super.prepare(for: segue, sender: sender)
guard let navigationController = segue.destination as? UINavigationController else {
return
}
guard let chatBotController = navigationController.viewControllers.first as? ChatBotViewController else {
return
}
// Get the data from sender, if not found, create it there.
// Or if you don't pass it through sender, you can specify it here.
let fittoBottle = sender as? FittoBottle ?? FittoBottle()
chatBotController.fittoBottle = fittoBottle
}
}

How can I add a segue identifier to a programmatically modal transition?

I have a controller which is in the Main storyboard. When I click on a button, I call the displayBorneDetailsAction() action, it presents a modal view from another storyboard.
I would add a Segue identifier when I present my modal to pass data from my main view controller to my modal view controller (with prepareForSegue), but I don't know how to do it.
I tried to use performSegue(withIdentifier:), but it doesn't present the modal in the same way.
#IBAction func displayBorneDetailsAction(_ sender: Any) {
// open the modal of a borne
let storyboard : UIStoryboard = UIStoryboard(name: "Borne", bundle: nil)
let vc: BorneVC = storyboard.instantiateViewController(withIdentifier: "BorneVC") as! BorneVC
let navigationController = UINavigationController(rootViewController: vc)
navigationController.modalPresentationStyle = UIModalPresentationStyle.overFullScreen
navigationController.edgesForExtendedLayout = []
self.present(navigationController, animated: true, completion: nil)
}
You cannot add an identifier to a programmatical segue, since you are able to access the instance of the controller that is being presented. Simply do anything you want with the controller in the function where you present it.

Dismiss viewcontroller depends on presentation style (modal or push)

I did FoodTracker programmatically and here is the code that doesn't work for me.
func cancel(){
let isPresentingInAddMealMode = presentingViewController is UINavigationController
if isPresentingInAddMealMode {
dismiss(animated: true, completion: nil)
}
else if let owningNavigationController = navigationController {
owningNavigationController.popViewController(animated: true)
}
else {
fatalError("The MealViewController is not inside a navigation controller.")
}
}
Here is how it looks in the storyboard:
Actually it works modally when the plus button is pressed but it doesn't work with popviewcontroller. I pushed it in the navigation stack with didSelectRow in tableViewController.