Get title of selected tab in UITabBarController - objective-c

I have set the title for all five of my tabs in my AppDelegate file. I would like to access that title in another view within my application. I have the code below to output to the log window the selected index of that selected tab but what I'd really like to get is the title for that tab. I did have a look through the UITabBarController Class Reference and I didn't see anything that would allow me to do this.
What I am trying to avoid is some sort of switch or if...else statement where I hardcode values I have already manually set in another file.
- (void)viewDidLoad {
[super viewDidLoad];
AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
NSLog(#"The currently selected tab has an index of: %d", appDelegate.tabBarController.selectedIndex);
}
This code works as intended. It would just be ideal to see the title.

UIViewController* vc = appDelegate.tabBarController.selectedViewController;
NSString* tabTitle = vc.tabBarItem.title;
If the code is in the selected view controller it's even easier:
NSString* tabTitle = self.tabBarItem.title;

Related

Creating additional window in Objective - C

I have my viewcontroller with view with 2 buttons. If i press button i want to get new window with search bar + data from my DB. How can I achive it without new VC ?
You basically want to bring another view into your current view controller on the press of a button.
Here will be my approach :
Make a separate class for the view (in your case the search bar and the data from the DB). Also a separate XIB for this would be handy.
Let the class be named 'PopOver'
In Popover.m :
+ (PopOverView*) createInstance {
PopOverView *xibView = [[[NSBundle mainBundle] loadNibNamed:#"PopOverView" owner:self options:nil] objectAtIndex:0];
[xibView setFrame:CGRectMake(CGRectMinXEdge + 10, CGRectMinYEdge + 10, 200, 200)];
// adjust frame according to your need
[xibView setBackgroundColor:[UIColor redColor]];
return xibView;
}
Next : In your view controller, On the tap of the button you would add the following code :
- (IBAction)buttonTapped:(id)sender {
UIView *myPopoverView = [PopOverView createInstance];
AppDelegate *appDel = [UIApplication sharedApplication].delegate;
[appDel.window addSubview:myPopoverView];
}
NOTE : I added the 'PopOver' view to the app delegate's window instead of the VC because in your case you don't want the user to interact with the view controller when you are showing the 'Popover' window. In such cases, its better to present views in the app's window.
ALSO : You can animate your view while you present it. For this, refer this link : addSubview animation
Lastly, you will need to implement your search and your DB functionality within the PopOver view class. (Don't forget to add delegates between your VC and Popover).
Hope this helps.
Thanks !
window is created by default in app delgate when you create a project in xcode and whole app is running on that window.
If I am not wrong you want to create a view and add it on a window.
create a File->New->File->iOS(UserInterface), select view name it
"YourView"
create another File->New->File->iOS(Source), select CocoaTouch class,
name it
"YourView" subclass of "UIView".
YourView *viewObj = [[[NSBundle mainBundle] loadNibNamed:#"YourView" owner:self options:nil] objectAtIndex:0];
AppDelgate *appDelObj = [[UIApplication sharedApplication] delegate];
[appDelObj.window addSubview:viewObj];
your view added on window.

IBAction that create a new UIViewController that is identical to the current one

I am developing a simple drawing app that saves the user's change (paint) then allow the user to have a new empty page when clicking on "New Page" button.
I'm facing a problem while trying to create a new page..
I'm using the single view template and currently my app contains only one ViewController. I want a new ViewController that is identical to the current one (but without the user's change (the user paint)) to be generated automatically when clicking on the "new page" button.
It is kind of similar to the notepad app, except that it doesn't use a tableView. I've looked over a lot of NotePad app source code, but I can't find what I actually need!
I hope you can help
thanks in advance
try this:
- (IBAction)newPagePressed
{
UIViewController *newVC = [[self class] alloc] init];
[self.navigationController setViewCntrollers:#[newVC]];
}
you'll need to use UINavigationController to achieve it, otherwise you can try:
- (IBAction)newPagePressed
{
MyAppDelegate *appDelegate = (MyAppDelegate *)[[UIApplication sharedApplication] delegate];
UIViewController *newVC = [[self class] alloc] init];
appDelegate.rootViewController = newVC;
}

didSelectRowAtIndexPath, pushViewController and a little lable

I have a table controller in which I use didSelectRowAtIndexPath to navigate from the pushed cell to another view. In it I initialize new view controller and push some data in it. After that I do pushViewController.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
// Navigation logic may go here. Create and push another view controller.
ServicesModel *service = [services objectAtIndex:indexPath.row];
ServiceViewController *serviceViewController = [self.storyboard instantiateViewControllerWithIdentifier:#"ServiceView"];
serviceViewController.serviceModel = service;
NSLog(#"Set model %#", service.title);
// Pass the selected object to the new view controller.
[self.serviceController pushViewController:serviceViewController animated:YES];
}
In my ServiceViewController I have a label serviceTitle and ServiceModel property for selected service
#property (weak, nonatomic) IBOutlet UILabel *serviceTitle;
#property (strong, nonatomic) ServiceModel *serviceModel;
Using viewDidLoad I'm trying to change text of the label
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
NSLog(#"viewDidLoad %#", self.serviceModel.title);
self.serviceTitle.text = self.serviceModel.title;
}
Also I'm trying to access model in viewDidAppear
- (void) viewDidAppear:(BOOL)animated
{
NSLog(#"viewDidAppear %#", self.serviceModel.title);
}
but when view opens, label is empty. Why? What am I doing wrong? The most strange is the log:
(-[ServiceViewController viewDidLoad]) (ServiceViewController.m:43) viewDidLoad (null)
(-[ServicesTableViewController tableView:didSelectRowAtIndexPath:]) (ServicesTableViewController.m:127) Set model Google.com
(-[ServiceViewController viewDidAppear:]) (ServiceViewController.m:36) viewDidAppear (null)
It shows that viewDidLoad fires before I assign the model property. And in viewDidAppear model property is still null. How it can be?
You have two problems. The first one, as 0x7fffffff mentioned, is that you're instantiating your controller incorrectly (it should be initWithNibName:bundle: if made in a xib, and like 0x7fffffff said if in a storyboard).
Second, you can't access the label in serviceViewController from didSelectRowAtIndexPath, because its view has not been loaded yet. So, instead of setting the label in didSelectRowAtIndexPath, you should have a string property in serviceViewController, and give it the value service.text. Then in viewDidLoad, you can populate your label with that string.
Is the label missing altogether, or do you see it and it just didn't receive updated text? If the label is missing, then it's probably a problem in how you're creating the view controller. If for example, you're using storyboards, you should be accessing the view controller like this:
ServiceViewController *controller = [self.storyboard instantiateViewControllerWithIdentifier:#"SomeStoryBoardID"];
Instead of this:
ServiceViewController *serviceViewController = [[ServiceViewController alloc] init];
If however, you can see the label, but it just hasn't updated it's text, the first thing you should to is examine the connections inspector in Interface Builder, and verify that the IBOutlet for the label is properly linked.

how to display various view controllers (each having its respective navigation controller) using storyboard ID

I'm working on my first app. Here's what I want to accomplish:
There will be a menu with several different options. For simplicity, assume this is comprised of UIButtons with IBAction outlets and the functionality exists to pull up the menu at any time.
Each menu button, when pressed, should display a different navigation controller's content. If the user brings up the menu and makes a different selection, the navigation controller in which he is currently operating should not be affected; the newly selected navigation chain is displayed on top of the old, and through the menu, the user can go back to the view where he left off on the previous navigation chain at any time.
visual illustration (click for higher resolution):
Please note that there are 3 different navigation controllers/chains. The root view controller (which is also the menu in this simplified version) is not part of any of them. It will not suffice to instantiate one of the navigation chains anew when it has been previously instantiated, and here's why: if the user was on screen 3 of option 2 and then selects option 1 from the menu and then selects option 2 (again) from the menu, he should be looking at screen 3 of option 2--right where he left off; the view controller he was viewing when he previously left the navigation chain should be brought back to the top.
I can make a button instantiate and present a view controller from the storyboard if there is NOT a navigation controller:
- (IBAction)buttonPressed:(id)sender {
UIViewController *controller = [self.storyboard instantiateViewControllerWithIdentifier:#"View 2"];
[self presentViewController:controller animated:YES completion:nil];
}
However, I can't figure out how to make those two methods work with a navigation controller involved. Moreover, I'm not sure those two methods are the right choice, because I won't always want to instantiate a new view controller: when a menu button is pressed, a check should be performed to see if the view (navigation?) controller with the corresponding identifier has already been instantiated. If so, it should simply be made the top view controller.
In summary, here are my questions:
1) How should I instantiate and display a view controller that is embedded in a navigation controller, preferably using a storyboard ID? Do you use the storyboard ID of the navigation controller or of the view controller?
2) How should I check whether an instance already exists? Again, should I check for an extant navigation controller or for a view controller, and what's the best method to do so?
3) If the selected navigation chain has already been instantiated and is in the stack of view controllers somewhere, what is the best method for bringing it to the top?
Thank you!!
side note -- it would be nice to know how to paste code snippets with indentation and color formatting preserved :)
As Rob has suggested, a tab bar controller would make a good organising principle for your design.
Add a UITabBarController to your storyboard, give it a storyboard iD. Assign each of your three sets of viewControllers ( with their respective navController) to a tab item in the tabBarController.
UITabBarController
|--> UINavigationController --> VC1 ---> VC2 -->
|--> UINavigationController --> VC1 ---> VC2 -->
|--> UINavigationController --> VC1 ---> VC2 -->
In you app delegate make a strong property to hold your tab bar controller's pointer. As the tab bar controller keeps pointers to all of it's tab items, this will take care of state for each of your sets of viewControllers. You won't have to keep separate pointers for any of them, and you can get references to them via the tabBarController's viewControllers property.
#property (strong, nonatomic) UITabBarController* tabVC;
Initialise it on startup
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
UIStoryboard storyBoard =
[UIStoryboard storyboardWithName:#"MainStoryboard_iPhone" bundle:nil];
self.tabVC = [storyBoard instantiateViewControllerWithIdentifier:#"tabVC"];
//hide the tab bar
for (UINavigationController* navController in self.tabVC.viewControllers)
[navController.viewControllers[0] setHidesBottomBarWhenPushed:YES];
return YES;
}
An alternative way to hide the tab bar is to check the "Hides bottom bar on push" box in the Attributes Inspector for each of the (initial) viewControllers. You don't have to do this for subsequent viewControllers, just the first one that will be seen in that tab item.
Then when you need to navigate to one of your navController groups…
- (IBAction)openTab:(UIButton*)sender {
AppDelegate* appDelegate =
(AppDelegate*)[[UIApplication sharedApplication] delegate];
if ([sender.titleLabel.text isEqualToString: #"Option 1"]) {
appDelegate.tabVC.selectedIndex = 0;
}else if ([sender.titleLabel.text isEqualToString: #"Option 2"]){
appDelegate.tabVC.selectedIndex = 1;
}else if ([sender.titleLabel.text isEqualToString: #"Option 3"]){
appDelegate.tabVC.selectedIndex = 2;
}
[self presentViewController:appDelegate.tabVC
animated:YES completion:nil];
}
(this example uses presentViewController, your app design may navigate this in other ways…)
update
If you want to do this without a tab bar controller, you can instantiate an array holding pointers to each of your nav controllers instead:
UINavigationController* ncA =
[storyboard instantiateViewControllerWithIdentifier:#"NCA"];
UINavigationController* ncB =
[storyboard instantiateViewControllerWithIdentifier:#"NCB"];
UINavigationController* ncC =
[storyboard instantiateViewControllerWithIdentifier:#"NCC"];
self.ncArray = #[ncA,ncB,ncC];
Which has the benefit of not having a tab bar to hide…
Then your selection looks like…
- (IBAction)openNav:(UIButton*)sender {
AppDelegate* appDelegate =
(AppDelegate*)[[UIApplication sharedApplication] delegate];
int idx = 0;
if ([sender.titleLabel.text isEqualToString: #"option 1"]) {
idx = 0;
}else if ([sender.titleLabel.text isEqualToString: #"option 2"]){
idx = 1;
}else if ([sender.titleLabel.text isEqualToString: #"option 3"]){
idx = 2;
}
[self presentViewController:appDelegate.ncArray[idx]
animated:YES completion:nil];
}
1 / You can instantiate a viewController in your viewDidLoad method of your main viewController, so it will be instantiate 1 time only.
Now if you want display your controller, you would better push it :
- (IBAction)buttonPressed:(id)sender {
// Declare your controller in your .h file and do :
controller = [self.storyboard instantiateViewControllerWithIdentifier:#"View 2"];
// Note you can move this line in the viewDidLoad method to be called only 1 time
// Then do not use :
// [self presentViewController:controller animated:YES completion:nil];
// Better to use :
[self.navigationController pushViewController:controller animated:YES];
}
2 / I'm not sure, but if you want to check if an instance already exist just check :
if (controller) {
// Some stuff here
} // I think this checks if controller is initiated.
3 / I know it's not a good advice but I would tell you to not worry about checking if your controller already exist, because I think it's easier to access your viewController by using the 2 lines again :
controller = [self.storyboard instantiateViewControllerWithIdentifier:#"View 2"];
[self.navigationController pushViewController:controller animated:YES];
4 / I'm not sure if colors can be used here because of a specific style sheets.
I'm not sure to really have the good answer to your question but I hope this will help you.

How to update a detailView in a splitViewController?

I'm trying to update a detailView in a splitViewController.
This is what I try:
//Get the application delegate
AppDelegate *delegate = [[UIApplication sharedApplication] delegate];
//Get the masterViewController
MasterViewController *master = [delegate.splitViewController.viewControllers objectAtIndex:0];
This seems to work fine so far.
Then I try to update a label in the detailViewController by doing this:
master.detailViewController.myLabel.text = #"someText";
But this doesn't work.
So how is the right way to access the outlets of in the detailView?
Thanks for help.
Define the DetailViewController; in your example the detailViewController is:
DetailViewController *detailViewController = [delegate.splitViewController.viewcontrollers objectAtIndex: 1];
You shouldn't be reaching inside another view controller and changing things. Instead, simply send a message to the DetailViewController, e.g. [detailViewController setCurrentEntry:selectedEntry]. Better yet, use notifications or KVO to let the DetailViewController observe the selection in the master list. This way, the two view controllers need not refer to each other at all; this is handy when you want to rearrange your app's layout, or use one view controller in isolation, say, in a modal view. Plan for the future.