Open (i.e. go to) specific segue from UITabBarController (Swift) - ios

In Swift 2, Xcode 7.1
As the image above, TabBarController will be the main view. Anonymous user can go to the home tab, if they click on the "Me" (Profile) tab, I want the app will pop up the new login segue (navigation controller). User need to login 1st before they can go into the "Me" tab.
Currently I have override the TabbarControllerDelegate in the TabBarController class, which as below (I use Parse, so user = PFUser.currentUser(), Parse will cache the user):
func tabBarController(tabBarController: UITabBarController, shouldSelectViewController viewController: UIViewController) -> Bool {
if (viewController is MeViewController && user == nil) {
print("login \(viewController)")
// How could I go to the Login Segue from here?
return false
} else {
return true
}
}
How could I achieve my goal from here? Or any better advice? Btw, I am not able to use performSegueWithIdentifier with the TabBarController class unless I use it within the ProfileViewController class (UIViewController) to achieve it. But if I did that, the app will display the view in 'Me' Tab first then go to the 'Login' segue, which is not what I wanted
It will be great thanks for any advices

If you want the user to not be able to go to me before login, you can just do a check with a static bolean which will be initialize in app delegate.
Then if the bolean is set to false (default value), you can invoke the your login popup.
No point here to perform a segue, just put an identifier on the view in the storyboard (identity inspector => storyboard id) and then you can invoke this particular view of the storyboard like this :
let SB = UIStoryboard(name: "MyStoryboard", bundle: nil)
let controller = SB.instantiateViewControllerWithIdentifier("MyId")
self.presentViewController(controller, animated: true, completion: nil)
Segues are only for views which are linked to each other, i personnaly almost never used them.

I recommend that you make the login UINavigationController segue come directly from the UITabBarController instead of on the "Me" controller. This is because you can't modally present your login controller through the "Me" controller if its not on the screen.
Give the segue an identifier (eg. "my-identifier"):
Click on the segue in the storyboard editor and fill in the identifier field in the right sidebar.
After this is configured correctly, the following code will perform the login segue (note the use of tabBarController since you should have the segue configured from the UITabBarController:
tabBarController.performSegueWithIdentifier("my-identifier", sender: self)

Related

Xcode, where to assign the segue identifier

Pardon me for beginner's question.
I know I can switch to another screen (ViewController) like this
self.performSegueWithIdentifier ("SecondViewController", sender: self)
but I can't seem to find where to assign my 2nd screen the id, I just find Storyboard ID, is that it?
I've already tried, only received a crash with the following error:
Receiver () has no segue
with identifier 'SecondViewController'
Any idea? thanks
Segue Identifier is not the same as storyboard ID, storyboard ID used when you want to create a View Controller based on that specific storyboard -and it has to be unique, unlike the segue identifier-.
If you already know how to create a segue, you can skip this part.
Adding a segue between two viewControllers:
From the Interface Builder, press the ctrl and drag between the two View Controllers that you want to link (make sure that you are dragging from the view controller itself, not the its main view). You should see:
Choose the "Show" -for instance-, the output should look like this:
As shown above, the arrow that surrounded by the red rectangle is the segue.
Additional note: if you selected the "Show" option, you have to embed your first view Controller in a Navigation Controller (select your first viewController -> Editor -> Embed In -> Navigation Controller), the output should looks like:
Because the "Show" means pushing into a navigation controller stack.
Assigning an identifier for the segue:
Select the segue, from the attribute inspector you'll see "Identifier" text field, that's it! make sure to insert the exact same name that used in performSegueWithIdentifier.
If you don't know where to find the attribute inspector, it is on the top right looks like:
Furthermore:
For adding multiple segues from one View Controller, follow the same process (ctrl + drag from the first controller to each other View Controller), the output should looks like:
In this case, you might face the issue how to recognize which segue has been performed, overriding prepare(for:sender:) method is the solution, you can make the checking based on the segue identifier property:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if (segue.identifier == "firstSegueIdentifier") {
// ...
} else if (segue.identifier == "secondSegueIdentifier") {
//...
}
}
which would be the name that you have added to the segue in the storyboard.
In your code
self.performSegueWithIdentifier ("SecondViewController", sender: self)
the string "SecondViewController" is looking like storyboard id . At the same place you have to write the segue identifier , not storyboard id .
Follow the Screenshot and assign segue identifier name by clicking on the segue on right top bar field. you can do like this
self.performSegueWithIdentifier ("WriteSegueIdentifierName", sender: self)
Similar to the answers provided, here's what it would look like in Xcode 12:
Select the segue link in Main Storyboard view
Navigate to the Attribute Inspector and add an Identifier (if one does not exist)
Add the Identifier to your code. Done!
When you link a View controller to another View controller in the storyboard, in the link between them you need to assign a segue identifier i.e "SecondViewController" only then your code will work.
Alternatively, you can also show another view controller through storyboard id using self.storyboard.instantiateViewControllerWithIdentifier("//storyboard id of that view controller") and then either use present/show view controller.
You can initiate viewController like this:
let viewController = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "Login")
self.present(viewController, animated: false, completion: nil)
Show Xcode screenshot
Click on Present Modally segue label... and on the Attributes Inspector input Identifier

Tab bar after login - Why does it look like this?

so I'm writing this app where I need to have a tab bar after the whole sign up/login part. I've looked around and I dont see anyone explaining me how to do this or why its happening: when I put the tab bar controller, it appears with no actual buttons, and also how should I connect the app to the tab bat controller? Either way, thats my main question. Am I missing something? Thank you!
i have also been developed the application using UITabBarController faced same difficulty how to implement attach login and signup view controller.
by few work around i finally able to achieve that i don't say it is the perfect way but i am using like that,
steps
make two Stroyboard
1.login.Stroyboard
2main.Stroyboard
3.now on homeviewcontroller.swift which is first tab of uitabbarcontroller
override func viewDidAppear(animated: Bool) {
guard (NSUserDefaults.standardUserDefaults().objectForKey(USER_INFO) != nil) else {//check user is logged in or not
//if user is not logged in present login.storyboard and do the logic there
let storyboard = UIStoryboard(name: "Login", bundle: nil)
let controller = storyboard.instantiateViewControllerWithIdentifier("LoginViewController") as UIViewController
target.presentViewController(controller, animated: true, completion: nil)
return
}
4. in loginviewcontroller and signupviewcontroller after sucessfull login or signup dissmiss your login.storyboard
self.dismissViewControllerAnimated(true) { () -> Void in
}
5.here the link of project -
https://drive.google.com/file/d/0B7APKZanPpc3OW92bzQ5QnRXdVU/view?usp=sharing

Segue Out of Navigation Controller

I am trying to leave the initial view controller, and go into the blank view controller. That is fine, but that would make the blank view controller also part of the navigation controller, which is not what I want. I want to segue out of the view controller.
In the view controller I try to segue out of, it pops it self, and when I try the method in the view will appear of the target view controller, self.navigationController?.topViewController returns itself, but self.navigationController?.popViewControllerAnimated(animated) doesn't work
If you have a navigationController do
self.navigationController?.popViewControllerAnimated(false)
Otherwise do
self.dismissViewControllerAnimated(false, completion: nil)
Update
Go to your Storyboard, select the ViewController you want to navigate to and add a storyboard id. Make sure the click "Use Storyboard ID"
Go to the class you want to navigate from and add the following code
let storyboard = UIStoryboard(name: "Main", bundle: nil)
// vc is the Storyboard ID that you added
// as! ... Add your ViewController class name that you want to navigate to
let controller = storyboard.instantiateViewControllerWithIdentifier("vc") as! ViewController
self.presentViewController(controller, animated: true, completion: { () -> Void in
})
Add this code in the action that you use when you want to navigate.
I believe this can be done without having to write any code at all. To Segue out of a Navigation Controller follow these steps:
Create a Segue from the View Controller that has a Navigation Controller as it's root view controller to the View Controller that you would like to go to next (without being inside the Navigation Controller)
Click on the new Seque
Open the Attributes Inspector
Choose 'Kind' -> 'Present Modally'
Choose 'Present' -> 'Over Current Context'

How can I segue or pop back to the second scene of the first tab in a tabbed app, from a scene on another tab?

I have a storyboard set up with a tab bar controller and three tabs. Each tab has a navigation controller. The first tab has three scenes. There is a button (log out) in a view on the third tab that I would like to segue to the second scene on the first tab (corresponding to the log in view controller and connected to the first scene via Show(e.g., Push).
Here is what I've tried:
self.tabBarController?.selectedIndex = 0
This works, insofar as I get back to the first tab's initial scene after tapping the UIButton. But since I want to get to the second scene, this is not a complete solution. I think the solution may be along the lines of:
self.tabBarController?.selectedViewController = LoginViewController()
or
self.tabBarController?.setViewControllers(self.LoginViewController, animated: true)
But I do not want to create another instance of a view controller.
Can I still use .selectedIndex to implement a solution?
A simple solution u can try is
1. Set a Global variable (i.e in App Delegate) name as isLogoutClick of type boolean.
2. While you are on third tab and click on logout button then make the global variable "isLogoutClick" as true.
3.and then navigate to first tab (1st scene) and on viewDidLoad just check the condition that
if(appDelegate.isLogoutClick)
{
push your view to next scene.
}
4. make false the value of isLogoutClick.
5. make sure at initially the value of isLogoutClick is false.
try this might it will help you.
After setting selectedIndex to 0, perform the segue you want (in this example, "loginSegue"). You can name your segue in the storyboard if you haven't already.
tabBarController?.selectedIndex = 0
if let someViewController = tabBarController?.viewControllers?[0] as? SomeViewController {
someViewController.performSegueWithIdentifier("loginSegue", sender: nil)
}
I'm not sure if this works for tabBarController because I've used this for my navigationController but should work the same.
if let tab = self.tabBarController?.viewControllers {
if let index = find(tab.map { $0 is LoginViewController }, true) {
let destination = tab[index] as LoginViewController
tabBarController?.presentViewController(destination, animated: true, completion: nil)
}
}
With a navigationController I would use popToViewController but I'm not sure how the tabBarController exactly works

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