CustomTabBarController not responding to delegate callbacks - iphone

I have created a custom UITabBarController by using Martin's tutorial.
My subclass FSTabBarController switches between view controllers, and acts normal as far as I can see.
The issue is, when I change my tabBarContoller to my subclass, It won't respond to my delegate;
- (void)tabBarController:(UITabBarController *)tabBarController didSelectViewController:(UIViewController *)viewController
If I change it back to UITabBarController -when I use the default UITabBarController- the delegates works as it should.
The custom subclass uses the below function to represent tab selection:
- (void)_buttonClicked:(id)sender
{
self.selectedIndex = [sender tag];
[self _updateTabImage];
}
Edit:
AppDelegate.h
...
#interface AppDelegate : UIResponder <UIApplicationDelegate,UITabBarControllerDelegate>
#property (strong, nonatomic) UIWindow *window;
#property (strong, nonatomic) FSTabBarController *tabBarController;
AppDelegate.m
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
...
self.tabBarController = [[FSTabBarController alloc] init];
self.tabBarController.viewControllers = [NSArray arrayWithObjects:peopleViewController,viewController,profileViewController, nil];
self.tabBarController.delegate = self;
...
}
- (void)tabBarController:(UITabBarController *)tabBarController didSelectViewController:(UIViewController *)viewController
{
// not called when FSTabBarController, called when UITabBarController !!
}

OK, downloaded the sample from his site and tested.
Yes you need to manually call the deleage from the subclass:
this is how you should change the buttonClicked function:
- (void)_buttonClicked:(id)sender
{
self.selectedIndex = [sender tag];
if (self.delegate) {
[self.delegate tabBarController:self didSelectViewController:self.selectedViewController];
}
[self _updateTabImage];
}

Related

Custom Delegate, dismiss popover from another view

I could use some help with custom delegates. I'm trying to make a protocol that sends a message to its delegate to dismiss the popover view. Here is what I'm trying.
In the popoverViewController.h
#import <UIKit/UIKit.h>
#protocol MyPopoverDelegate <NSObject>
-(void) didSelectLanguage;
#end
#interface Popover : UITableViewController{
id <MyPopoverDelegate> delegate;
NSMutableArray *languageData;
}
#property (nonatomic, assign) id <MyPopoverDelegate> delegate;
#end
.m
#synthesize delegate;
...
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
NSLog(#"You selected %#", [languageData objectAtIndex:[indexPath row]]);
[self.delegate didSelectLanguage];
}
...
And in the ViewController that presents the popover
#import <UIKit/UIKit.h>
#import "popoverViewController.h"
#interface ChoicesChoices : UIViewController <UIPopoverControllerDelegate, MyPopoverDelegate>{
UIPopoverController *popover;
}
- (IBAction)facebook:(id)sender;
- (IBAction)twitter:(id)sender;
- (IBAction)sms:(id)sender;
- (IBAction)copy:(id)sender;
- (IBAction)email:(id)sender;
- (IBAction)home:(id)sender;
- (IBAction)mute:(id)sender;
- (IBAction)note:(id)sender;
#property (nonatomic, retain) UIPopoverController* popover;
#end
and .m
#synthesize popover;
...
- (void)didSelectLanguage{
[popover dismissPopoverAnimated:YES];
NSLog(#"didSelectLanguage fired");
}
When I select a row in the table of the popover, didSelectLanguage does not get called. Any ideas on what I might be doing wrong? Thanks for your help.
Make sure you are setting your delegate to the be the view controller that is presenting your popover. Something like this in ChoicesChoices.m:
- (void)presentPopover
{
// assuming ARC for all allocations
Popover *myController = [Popover new];
myController.delegate = self;
self.popover = [[UIPopoverController alloc] initWithContentViewController:myController];
[self.popover presentPopover...]; // two flavors here, FromRect: and FromBarButtonItem:, that's left up to you to choose which one is correct.
}
Make sure you set the delegate in the presenting view controller when you create the instance of your custom class.
popover.delegate = self
Also, it looks like your property is a standard popover controller instead of an instance of your custom view controller.

tabBar didSelectItem seems not to be working

In my header file I have this:
#interface TabBarController : UIViewController <UIApplicationDelegate, UITabBarDelegate, UITabBarControllerDelegate>{
IBOutlet UITabBarController *tabBarController;
}
-(void)tabBar:(UITabBar *)tabBar didSelectItem:(UITabBarItem *)item;
#property (nonatomic, retain) IBOutlet UITabBarController *tabBarController;
#end
In my main file I have this:
#synthesize tabBarController;
-(void)viewDidLoad{
[super viewDidLoad];
self.tabBarController.delegate = self;
self.view = tabBarController.view;
}
-(void)tabBar:(UITabBar *)tabBar didSelectItem:(UITabBarItem *)item{
NSLog(#"rawr");
}
- (void)viewDidUnload {
[super viewDidUnload];
}
- (void)dealloc {
[tabBarController release];
[super dealloc];
}
#end
I have already connected my tabbarcontroller as a delegate to my file's owner in interface builder, but it still never calls the didSelectItem method.
Is there anything that I'm missing here?
I have already added tabBarController.delegate = self; and it still does not work.
-(void)tabBar:(UITabBar *)tabBar didSelectItem:(UITabBarItem *)item;
This method is a delegate method for UITabBar, not UITabBarController, so
self.tabBarController.delegate = self;
will not work.
Tab bar controller has its own UITabBar, but changing the delegate of a tab bar managed by a tab bar controller is not allowed, so just try UITabBarControllerDelegate method like this:
- (void)tabBarController:(UITabBarController *)tabBarController didSelectViewController:(UIViewController *)viewController
You need to add this:
tabbarcontroller.delegate = self;
Use UITabBarControllerDelegate instead of UITabBarDelegate and -tabBarController:didSelectViewController{} instead of tabBar:didSelectItem{}
Interface
#interface TabBarController : UIViewController <UIApplicationDelegate, UITabBarControllerDelegate, UITabBarControllerDelegate>{
IBOutlet UITabBarController *tabBarController;
}
#property (nonatomic, retain) IBOutlet UITabBarController *tabBarController;
#end
main file
#implementation TabBarController
#synthesize tabBarController;
/*other stuff*/
- (void)tabBarController:(UITabBarController *)tabBarController didSelectViewController:(UIViewController *)viewController{
NSLog(#"rawr");
}
/*other stuff*/
#end
Just set the delegate for the tab bar. You can do it by setting self.tabBarController.delegate = self; or using Interface builder do to the tabbarcontroller object (not bar) see the connection inspector and drag the connection on the file's owner.
You have synthesized the tab bar, so you now need to write: self.tabBarController.delegate = self;
There are many reasons, as indicated above, why it might not be working. Here is a more subtle reason. If you are creating your UI programatically (no storyboard or Xib) you need to set the screen of your UIWindow.
self.window = [[UIWindow alloc] init];
self.window.screen = [UIScreen mainScreen]; // <- The UITabViewController will not
// accept taps without this.
If you are using a Xib, I believe this is equivalent to having "Full Screen at Launch" selected. That has to be checked or I have noticed my Tabs don't work.
I had a non-working tab controller and this is what I had to do to get it working. None of the other answers on this page helped me. I suppose using a xib/storyboard is pretty rare these days (I think this was from iOS 5 days) but leaving here for the person that does and stumbles into this situation.

How to use multiple custom View Controllers with a Navigation Controller?

Basically, I have two view controllers inside the MainWindow.xib that can be viewed by clicking the Bar Button in my Navigation Controller. I wanted those two view controllers to be separated from the MainWindow.xib with their own header, implementation and xib files and still make Navigation Controller inside of MainWindow.xib work in them.
To better understand it, please see the codes below:
Thanks a lot!
TestAppDelegate.h
#import <UIKit/UIKit.h>
#interface TestAppDelegate : NSObject <UIApplicationDelegate>
{
//Navigation Controller
IBOutlet UINavigationController *navigationController;
//View Controllers
UIViewController *viewController;
UIViewController *viewController2;
UIViewController *viewController3;
}
#property (nonatomic, retain) IBOutlet UIWindow *window;
//Navigation Controller
#property (nonatomic, retain) IBOutlet UINavigationController *navigationController;
//View Controllers
#property (nonatomic, retain) IBOutlet UIViewController *viewController;
#property (nonatomic, retain) IBOutlet UIViewController *viewController2;
#property (nonatomic, retain) IBOutlet UIViewController *viewController3;
- (IBAction)next;
- (IBAction)next2;
#end
TestAppDelegate.m
#import "TestAppDelegate.h"
#implementation TestAppDelegate
#synthesize window = _window;
//Navigation Controller
#synthesize navigationController;
//View Controllers
#synthesize viewController;
#synthesize viewController2;
#synthesize viewController3;
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
// Override point for customization after application launch.
//Navigation Controller
[self.window addSubview:[navigationController view]];
[self.window makeKeyAndVisible];
return YES;
}
- (void)applicationWillResignActive:(UIApplication *)application
{
}
- (void)applicationDidEnterBackground:(UIApplication *)application
{
}
- (void)applicationWillEnterForeground:(UIApplication *)application
{
}
- (void)applicationDidBecomeActive:(UIApplication *)application
{
}
- (void)applicationWillTerminate:(UIApplication *)application
{
}
- (void)dealloc
{
[viewController release];
[viewController2 release];
[viewController3 release];
[navigationController release];
[_window release];
[super dealloc];
}
- (IBAction)next {
[navigationController pushViewController:viewController2 animated:YES];
}
- (IBAction)next2 {
[navigationController pushViewController:viewController3 animated:YES];
}
#end
Inside MainWindow.xib:
http://i52.tinypic.com/10xa45f.png
I normally don't touch MainWindow.xib. I suggest the following:
Create a MainController which will be your MainView that subclass UIViewController by going to File > New > New File. That will create a .h/.m and nib file for each ViewController. There add whatever UI you want for your app. For Example, add two buttons and wire those buttons to IBActions in your MainController. This should be declared and implemented in your MainController.{h/m}, respectively.
After that create another two ViewControllers, the same way.
The body of those IBActions should create an instance of the your ViewControllers and then push them.
It would look something like this:
YourViewController *yvc = [[YourViewController alloc] init];
[self.navigationController pushViewController:yvc animated:YES];
[yvc release];
Finally, you have to push the MainController in your AppDelegate and add your NavigationController to the view.
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
MainViewController *mvc = [[MainViewController alloc] init];
UINavigationController *unvc = [[UINavigationController alloc] init];
[unvc pushViewController:mvc animated:NO];
[mvc release];
[self.window addSubview:unvc.view];
[self.window makeKeyAndVisible];
return YES;
}
Set the "class" property in Interface Builder (third tab in the inspector, "Custom Class") to the name of the custom class you're planning to use, and then put the name of the .xib file you want to load from in the "NIB Name" (fourth tab).
The code you're using to push the viewController is alright. Make sure to never accidentaly dealloc any of the two UIViewController.
Speaking of which, keep in mind that this approach is keeping the ViewControllers always in memory, even when not in use. Another approach is to completely remove the IBOutlets for the two ViewControllers, and do something like:
- (IBAction)next
{
MyCustomViewController *customViewController = [[MyCustomViewController alloc] initWithNibName:<#NibName or nil#> bundle:[NSBundle mainBundle]];
[navigationController pushViewController:customViewController animated:YES];
[customViewController release];
}
This creates the object when needed (If I remember right, the UI elements from the xib are cached somewhere, so that may be irrelevant[citation needed]). Just something to keep in mind, depending on the frequency of use of your two ViewControllers.

Blank screen on device; simulator working fine

I am writing an iOS app with a navigation controller. When I open it up on the Simulator, it runs fine. When I run it on the device, a blank screen is displayed below the status bar. Plus I can't figure out where my RootViewController is made to be the default view (which I suspect is the root of my problem).
#class RootViewController;
#interface MyAppDelegate : NSObject <UIApplicationDelegate> {
UIWindow *window;
RootViewController *viewController;
UINavigationController *navigationController;
}
#property (nonatomic, retain) IBOutlet UIWindow *window;
#property (nonatomic, retain) IBOutlet UINavigationController *navigationController;
#property (nonatomic, retain) IBOutlet RootViewController *viewController;
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.
// Set the navigation controller as the window's root view controller and display.
self.window.rootViewController = self.navigationController;
[self.window makeKeyAndVisible];
// ...
return YES;
}
RootViewController.m
- (void)viewDidLoad {
[super viewDidLoad];
self.title = #"Main Menu";
}
No viewWillAppear, viewDidAppear, etc.
Displays a table of 0 elements.
- (UITableViewCell *)tableView:(UITableView *)tv
cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
tv.backgroundColor = [UIColor whiteColor];
UITableViewCell *cell;
if (indexPath.row == 0)
cell = newsCell;
else if (indexPath.row == 1)
cell = configureCell;
else if (indexPath.row == 2)
cell = aboutCell;
return cell;
}
- (NSInteger)tableView:(UITableView *)tv numberOfRowsInSection:(NSInteger)section
{
return 0;
}
#pragma mark UITableViewDelegate Methods
- (CGFloat)tableView:(UITableView *)tv
heightForRowAtIndexPath:(NSIndexPath *)indexPath {
return 84;
}
- (void) tableView:(UITableView *)tv
didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
if (0 == indexPath.row)
{
}
else if (1 == indexPath.row)
{
}
else if (2 == indexPath.row)
{
}
}
#pragma mark -
#pragma mark Memory management
- (void)didReceiveMemoryWarning {
// Releases the view if it doesn't have a superview.
[super didReceiveMemoryWarning];
// Relinquish ownership any cached data, images, etc that aren't in use.
}
- (void)viewDidUnload {
// Relinquish ownership of anything that can be recreated in viewDidLoad or on demand.
// For example: self.myOutlet = nil;
}
- (void)dealloc {
[super dealloc];
[tableView release];
[newsCell release];
[configureCell release];
[aboutCell release];
}
RootViewController.h
#interface RootViewController : UIViewController
<UITableViewDataSource, UITableViewDelegate>
{
UITableView *tableView;
IBOutlet UIView *displaySplashScreen;
IBOutlet UITableViewCell *newsCell, *configureCell, *aboutCell;
}
#property (nonatomic, retain) IBOutlet UITableView *tableView;
There are a few issues here. First, your AppDelegate header should read:
#class RootViewController;
#interface MyAppDelegate : NSObject <UIApplicationDelegate> {
UIWindow *window;
RootViewController *rootViewController;
}
#property (nonatomic, retain) IBOutlet UIWindow *window;
#end
Then, in the implementation, add the root to the navigation controller and the navController to the window like this:
#import "RootViewController.h"
#implementation MyAppDelegate
#synthesize window;
- (BOOL)application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
rootViewController = [[RootViewController alloc] init];
UINavigationController *navController = [[UINavigationController alloc]
initWithRootViewController:rootViewController];
[window addSubview:[navController view]];
[self.window makeKeyAndVisible];
return YES;
}
PengOne's answer is correct, except I'd make one small change. Do this:
#import "RootViewController.h"
#implementation MyAppDelegate
#synthesize window;
- (BOOL)application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
rootViewcontroller = [[RootViewController alloc] init];
UINavigationController *navController = [[UINavigationController alloc]
initWithRootViewController:rootViewController];
self.window.rootViewController = navController;
[self.window makeKeyAndVisible];
return YES;
}
It's a better way to show a nav controller. As PengOne also said, it has to be a problem with your Interface Builder file. Unhook everything then hook it up again to see if the problem persists. If it does, check to make sure everything is named correctly. Good luck!

My UITabBarController's didSelectViewController method is not getting called?

Here is my code stub for my app-delegate.m -- it never gets called.
- (void)tabBarController:(UITabBarController *)tabBarController didSelectViewController:(UIViewController *)viewController {
NSLog(#"%s", __FUNCTION__);
}
It is defined in this app-delegate.h
#interface OrioleAppDelegate : NSObject <UIApplicationDelegate, UITabBarControllerDelegate> {
UIWindow *window;
UITabBarController *tabBarController;
}
#property (nonatomic, retain) IBOutlet UIWindow *window;
#property (nonatomic, retain) IBOutlet UITabBarController *tabBarController;
#end
Did you make a connection between your UITabBarController and your application delegate?
- (void)applicationDidFinishLaunching:(UIApplication *)application
{
...
tabBarController.delegate = self;
...
}
If your ViewController is a UITabBarController, you need to set self as it's delegate because you can't change the delegate of the UITabBar directly.
For example, in the ViewDidLoad of your UITabBarController :
- (void)viewDidLoad
{
[super viewDidLoad];
self.delegate = self;
}
I added the following tabBarController.delegate = self; and all is well. I hope this is helpful to others.
- (void)applicationDidFinishLaunching:(UIApplication *)application {
// Add the tab bar controller's current view as a subview of the window
tabBarController.delegate = self;
[window addSubview:tabBarController.view];
}