How can I create two segues for a single button in a view controller? - ios

I have a root view controller - which is a simple page presented to the user. In this page, there is a UIBarButton that goes to the user profile page.
When the user is in its profile, he/she'll have a back button that will allow him/her to go back to the root view controller.
However, the root view controller is different for admins and clients (there is one standard view controller for admins and one standard view controller for clients).
How can I create two segues that are triggered by the 'Back' profile button? I mean, depending on who is currently logged in (an admin or a client), I would like to go back to their respective pages.
The client cannot go back to the admin's page and neither vice versa.
Is there any way to create these two segues? Or even another/better way? I have tried to do that using storyboard, but when I create the second segue, it deletes the first one linked to the button.

You cannot do that but there is other way for that, create two segue bwtween SenderViewController and DestinatrionViewController. After that set action for your button and perform the segue according to your requirements.
#IBAction func buttonAction(_ sender: UIButton) {
if condition {
self.performSegue(withIdentifier: "identifier1", sender: nil)
}
else {
self.performSegue(withIdentifier: "identifier2", sender: nil)
}
}

Going off of Nirav D's answer, use an if...else with the condition that they are an admin or client. But don't control+drag from the button itself, control+drag from the ViewController as seen in the images below.

you should handle it in your code.
#IBAction func backClick() {
if isAdmin /* check condition here */ {
// admin work
} else {
// normal user work here
}
}
Then let create segue from storyboard and give it an identifier.
If you want perform segue, let use
performSegue(withIdentifier: "identifier", sender: nil)
if you want go back.
dismissViewControllerAnimated(true, completion: nil)
Hope it help.

Related

IOS swift UIBarButtonItem action

I've a table view with navigation controller embedded in. I've added a UIBarButtonItem (add) button. When I click this button it opens a new view where user enters the data and submits it (which makes a web service call) and returns back to the previous view. This navigation happens as shown below,
func addTapped(_ sender:UIBarButtonItem) {
print("Called Add")
let vc = (storyboard?.instantiateViewController( withIdentifier: "newNote")) as! newNoteVC
self.navigationController?.pushViewController(vc, animated: true)
}
And in new view I do following,
#IBAction func saveButton(_ sender: UIButton) {
if (self.noteDescription.text?.isEmpty)! {
print("Enter missing note description")
return
} else {
let desc = self.noteDescription.text
self.uploadNote(noteText: desc!, noteDate: self.dateInMilliseconds)
self.navigationController?.popViewController(animated: true)
}
}
This way a record gets saved and a view gets popped from the navigation controller stack but only thing I don't how to do is refresh the table view data in the parent view (where I might need to make a new http service call to read all the records).
I hope I'm able to explain the issue? Any help is appreciated.
As mentioned in the comments, making a service call just to update the tableview might be a overkill. However, if this is the business scenario which needs to be implemented, you can do the same in
func viewWillAppear
in the parent view controller. You can make the service call in this method and reload the table view with the data.
You would also need to check the overall navigation of the application as making service calls in viewWillAppear method is not a good approach as these gets called everytime the view is shown. For Ex: If coming back from a navigated view then also the method is called.

How to add a tabbar after a user action

I have an app that doesn't have to show any tab when the user isn't logged in. I'm facing many issues with this functionality. First of all, I had embed the views, after the login screen, into a tab bar controller and everything was showing ok, except when I had implemented the login feature. As it's an async call, I had to wait until the credentials were validated. I wasn't able to do this in the shouldPerformSegue method or any other method provided by apple because you can't block the main thread until the async stuff is done, so the segue has to be done programaticaly in an IbAction:
#IBAction func doLogin(sender: AnyObject) {
userIsLogged = false
let apiCall = webApi()
apiCall.callCheckIsUserLogged(nil, password : self.passwordField.text, email: self.mailField.text){ (ok) in
if ok {
if(userIsLogged == true){
dispatch_async(dispatch_get_main_queue()) {
self.performSegueWithIdentifier("loginUser", sender: self)
}
}else {
NSOperationQueue.mainQueue().addOperationWithBlock{
print("User not logged in")
self.alert.message = "Please enter valid credentials"
self.displayAlert()
}
}
}
}
}
But this has driven me to another issue: after the programatic segue, my tab bar controller was disappearing, and after read a while it looks like the only way to avoid this is to embed your tab bar controller into a navigation controller. So I did it, but now, I got many new issues. First of all I got two navigation controllers, the one who is at the very beginning of the project and this new one I have embed into the tab bar controller. A picture will illustrate this better than my words:
Now I have two navigation controllers, and I don't know how to hide the top one. Already tried:
self.navigationController?.navigationItem.hidesBackButton = true
But is hiding the arrow and I need to hide the other one navigation controller. But the best thing indeed would be to see the best approach for this kind of cases, when you want to add a tabBar controller embed into a navigation controller in the middle of the project.
Thanks all
I guess you can take another approach. Make login storyline and your app storyline distinct.
Have a storyboard for your login procedure, and another storyboard for your home (or whatever you like) and manage them in AppDelegate.
This is how i did it:
if /* user must log in */ {
self.window?.rootViewController = loginStoryboard?.instantiateInitialViewController()
self.window?.makeKeyAndVisible()
}
else {
self.window?.rootViewController = homeStoryboard?instantiateInitialViewController()
self.window?.makeKeyAndVisible()
}
Put this code in a method (for example called manageRootViewController()) and call it at app launch, or after your login. (You can also add custom animations if you like)

Unwind Segue Not Working in page view controller, Have Checked Other Posts

So I have a page view controller setup and each of my pages has a back button that calls an unwind segue which when arriving at the root page controller calls another unwind segue to get back to the main menu:
func backButtonAction(sender:AnyObject!){
println("ok")
dispatch_async(dispatch_get_main_queue()) {
self.performSegueWithIdentifier("unwindGameContentViewController", sender: self)
}
//self.performSegueWithIdentifier("loadFollowPatternViewController", sender: self)
//self.performSegueWithIdentifier("unwindGamesContentViewController", sender: self)
}
and
#IBAction func unwindToViewController(sender:UIStoryboardSegue){
println("blow")
self.performSegueWithIdentifier("unwindGamesViewController", sender: self)
}
On the first page clicking the back button functions as usual but then the second and third page of the view controllers do not function at all. The backButtonAction function is called and the ok is printed but the unwind does not take place and the blow print line is not printed either.
I get no errors or warnings about storyboard or anything else.
My code used to work before Xcode 6.3 came out with the updated swift language, however I am not sure whether I broke the code before then or the update broke it.

Multiple unwind in the same button - Swift

I would like to know if it is possible to assign two different unwind method at the same button. For example:
I have this views navigations:
Home->A->B
Home->C->B
A and C views navigates to B, but then I want to return to previous views using the same B view and controller.
It is possible?
I have been thinking about write assign unwind method to the button programmatically depending what view comes.
Thanks in advance
I'm sorry about my english, is not good.
Here's a Swift solution that worked well for me. The code below only works if you hookup your segues correctly in the storyboard and in code. Checkout this page for great explanations on setting up unwind segues.
In summary:
You're accessing the same view from multiple other views. So, when you segue to a view, you can pass the source view controller (the view that you're currently in) to a property in the view that you're going to.
In your view that you will unwind out of, you can check the property holding the info (the class) on where you came from, and then perform a segue based on what view it is.
The code: (using ex: Home -> A -> B or... Home -> C -> B)
Note: B is the view that will unwind to multiple different views.
In A or C: (code works the same way in both views)
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "segueIdentifierInViewAthatGoesToViewB" {
let controller:B = segue.destinationViewController as! B
//the code below passes our current view controller class to a property in view B.
//So, view B will know what view we came from.
//In our example, we're coming from view A or C
controller.viewControllerNavigatedFrom = segue.sourceViewController
}
}
In B:
//setup an IBAction that will check the source view controller (that we passed when we segued to this view) and perform a segue based on where we came from. You can hook this up to a button or anything you want really.
//isKindOfClass(A) - "A" would be the name of your class
//setup a property to receive the view controller class where we are coming from
var viewControllerNavigatedFrom:AnyObject?
#IBAction func myButtonPressed(sender: AnyObject) {
if self.viewControllerNavigatedFrom!.isKindOfClass(A) {
//Unwind to view A
performSegueWithIdentifier("unwindFromBbackToA", sender: sender)
}
else if self.viewControllerNavigatedFrom!.isKindOfClass(C) {
//Unwind to view C
performSegueWithIdentifier("unwindFromBbackToC", sender: sender)
}
}
Although, question isn't very clear. But what I could understand is that you want to navigate back to the previous view i.e. B>C or B>A depending upon where user came from.
If so, then check the UINavigationController. It keeps track of the navigation history and automatically adds a back button. Kind of like the back button in our browsers.
Here is a tutorial, although a bit old: Link

performSegueWithIdentifier has no segue with identifier

I encountered a crash while testing my app. The following image is my storyboard:
I have the code in View Controller:
#IBAction func unwindToHomeScreen(segue:UIStoryboardSegue) {
}
The view of "Add new Item" have a "Cancel" button, I controlled-drag it to the "Exit" icon at the top and link to unwindToHomeScreen, it works fine.
The "Add new Item" has a class AddTableViewController and the code I wrote inside:
#IBAction func save() {
// Execute the unwind segue and go back to the home screen
performSegueWithIdentifier("unwindToHomeScreen", sender: self)
}
I controlled-drag the "Save" button to the func, but the app crash when I click the button
I can use dismissViewControllerAnimated(true, completion: nil) instead, but I just wonder why performSegueWithIdentifier can't work?
I read the code at dropbox.com/s/hpybgg9x67rtqng/foodpinstatictable.zip?dl=0 and try to make one and using performSegueWithIdentifier like this example for practicing, I didn't see the segue identifier at her, what is the difference?
You haven't actually given that segue an identifier. unwindToHomeScreen is a function that you can call; what you're looking for is your segue identifier, which is set in Interface Builder like this:
In this example, I have a button wired to the next view via Interface Builder like you describe ("Interface Builder") and a button that is wired to this IBAction in my view controller ("Programmatically"):
#IBAction func goToNextView(sender: UIButton!) {
self.performSegueWithIdentifier:("go", sender: self)
}
In any case, what you're missing is the actual identifier, which can be set in the attributes of a segue created in Interface Builder.
Swift 4:
Sometimes we must clean the build folder and then try again.
Worked for me after ctrl-dragging the new segue and giving it a name, then using it programatically as:
performSegue(withIdentifier: "goToMyNewViewController" , sender: self)
I found that because I renamed my view controller, I needed to delete and recreate the segue.
A possible issue with iOS 12 and earlier (iOS 13 seems not to suffer from the same issue) might come from the fact that performSegue(withIdentifier:,sender:) is called from the view controller viewdidLoad() callback.
You absolutely must invoke it from the viewDidAppear(_ animated: Bool) callback in order to avoid the question-mentioned crash.
That will certainly save hours of hair-puling…
in my case reorder the Embed in
Tab bar controller
Navigation controller
vc (contains button - tapping button initiates a "show, e.g. push" segue)
Too fix the title in the navigationBar
I had the same issue.
All I did was:
I selected the segue indicator in the storyboard.
Deleted it.
Then created a new segue with the same identifier. Boom, it works.
I had it all wired up correctly. It was just that the viewController I was segueing from, was NOT instantiated from the storyboard. I had it instantiated pragmatically.
I initially had it written as:
let vc = DeviceVC()
Had to change it to:
let sb = UIStoryboard(name: "Main", bundle: Bundle(for: DeviceVC.self))
let vc = sb.instantiateViewController(identifier: "DeviceVC") as! DevieVC
for me --> click on the relation-arrow between view controllers and then select attribute inspector, there is identifier give name and select push class done...

Resources