How to access tabBarController from AppDelegate.m? - ios

This is my storyboard:
I am trying to access tabBarController from a method inside AppDelegate.m
This is AppDelegate.h:
#import <UIKit/UIKit.h>
#import <FacebookSDK/FacebookSDK.h>
#import "STAlertView.h"
#interface demo_AppDelegate : UIResponder <UIApplicationDelegate>
#property (strong, nonatomic) UIWindow *window;
#property (nonatomic, strong) STAlertView *av;
#end
And this is AppDelegate.m:
#import "demo_AppDelegate.h"
#import "demo_Friends_ViewController.h"
#implementation demo_AppDelegate
-(void)showFriendReqAlert:(NSNotification *)pNotification{
NSLog(#"Hello from showFriendReqAlert:");
NSLog(#"Root: %#", [self.window.rootViewController.navigationController.tabBarController viewControllers]);
}
....
....
....
....
#end
My main motive is when this method showFriendReqAlert: is called, a red badge is shown to the third tab bar item which is Friends. But whenever i try to select tabBarItem, it says null in NSLog.
I have also tried the following:
self.window.rootViewController.navigationController.tabBarController
self.window.rootViewController.tabBarController
but nothing works. Any help?
Thanks!

I believe (sorry for believing here ;-) that the TabBarController should be your first controller and your navigationBarController must come afterwards as it does not make much sense for the navigationController (if you change a tab) what to push/pop.
I suggest that you remove your first DemoViewController and following NavigationController and that your first Controller is your TabBarController (simply set "Is Initial View Controller" in IB).
Then you can access your tabBar like this:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
UITabBarController *tbc = (UITabBarController *)self.window.rootViewController;
}
Swift 5:
guard let tabBarController = window?.rootViewController as? UITabBarController else { return }

Related

iOS - pushViewController not working after conversion to xCode 9 / iOS 11

I saw my iOS app isn't allowed to be downloaded from the app store with the most recent upgrade to iOS 11, so I'm trying to update it. I have it in Xcode 9, and I've managed to now get the app started on my iPhone 6. However, I can't seem to get it to display after my initial screen display.
For example, the initial display successfully displays and shows a button called "start". That should pop up another display when you press it, but it doesn't (although it is reaching the code which displays it).
Here's the code, in a class named "StartController.m", which should be calling up the display:
NSLog(#"nav controller = %#", self.navigationController);
// push question controller onto the stack
[self.navigationController pushViewController:questionController animated:YES];
// the nav controller owns it now, we can release it
[questionController release];
Debugging shows this code is successfully called when the button is pressed, but after the release of questionController, nothing happens.
Here's the declaration of the questionController in StartController.h:
#interface StartController : UIViewController <ADBannerViewDelegate>{
QuestionController *questionController;
And here's the declaration of the same in StartController.m:
#implementation StartController
#synthesize questionController, settingsController, nextLevelViewController, appState;
The initial view (with the "start" button) is successfully displayed with this code in the "didFinishLaunchingWithOptions" method of the app delegate:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.
// create the start controller
self.startController = [[StartController alloc] init];
// transfer to it - not animated because it's the first view
[navController pushViewController:startController animated:NO];
// add the current nav controller view to the window view heirarchy
// [window addSubview:navController.view];
[self.window setRootViewController:startController];
// release becasause now the navController has it
[startController release];
// show the start controller
[self.window makeKeyAndVisible];
return YES;
}
For reference, here's the declaration of the navController in the app delegate header:
#interface QuizAppDelegate : NSObject <UIApplicationDelegate> {
UIWindow *window;
UINavigationController *navController;
StartController *startController;
}
#property (readonly) BOOL iPad;
#property (nonatomic, retain) IBOutlet UIWindow *window;
#property (nonatomic, retain) StartController *startController;
#property (nonatomic, retain) IBOutlet UINavigationController *navController;
And here's the declaration in the implementation:
#implementation QuizAppDelegate
#synthesize window;
#synthesize startController;
#synthesize navController;
I tried not to post too much code for fear of obscuring the problem, but I'll add it if requested. Any ideas what the problem might be?

tabBarController didSelectViewController in AppDelegate is not called

I have used the Xcode tab bar controller template and am trying to detect when a user selects a tab in my tab bar controller. In AppDelegate.h I have:
#import <UIKit/UIKit.h>
#interface AppDelegate : UIResponder <UIApplicationDelegate, UITabBarControllerDelegate> {
UITabBarController *tabBarController;
}
#property (strong, nonatomic) UIWindow *window;
#property (nonatomic, retain) IBOutlet UITabBarController *tabBarController;
#end
and in AppDelegate.m I have:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
tabBarController.delegate = self;
return YES;
}
- (void)tabBarController:(UITabBarController *)tabBarController
didSelectViewController:(UIViewController *)viewController
{
NSLog(#"Selected tab bar button!");
}
I have not connected any outlets for the Tab Bar Controller scene listed in Main.storyboard because I couldn't figure out the right connection to make, if one is even necessary. I also haven't made any references to this delegate method in my FirstViewController or anywhere else, because the various ways I tried to do that didn't work. Could someone help me understand how to get this working?
You can add tab bar controller by selecting UIViewController(FirstViewController in your case) and choose Editor >> Embed In >> Tab Bar Controller.
Eliminate the UITabBarController *tabBarController; declaration in AppDelegate.h (line 4) and replace
tabBarController.delegate = self;
with
self.tabBarController.delegate = self;
in AppDelegate.m.

How to transition between any two ViewControllers in Cocoa Touch?

I'm fairly new iOS development. I have multiple viewControllers for my app, for example -
A login screen
A main / my profile screen
A leader board / standings screen
etc..
Each of these screens has its own viewController.
What's the best way to transition between any two arbitrary viewControllers with an animation?
My current approach is -
Keep a reference to each viewController in AppDelegate.m
Keep changing the window's root controller as needed
This is both cumbersome and seems pretty inefficient, plus I'm not quite sure how to incorprate animated transitions here.
I see some examples with UINavigationController, but it seems like that operates as a "stack" of views that you can go into and then back out of. I'm not looking to keep a history here, just switch from any view to another.
Any good ways to accomplish this?
Thanks!
Try this Code.
AppDelegate.h
#import <UIKit/UIKit.h>
#import "LoginViewController.h"
#interface AppDelegate : UIResponder <UIApplicationDelegate>
#property (strong, nonatomic) UIWindow *window;
#property (strong,nonatomic) UINavigationController *navigationController;
#property (strong,nonatomic) LoginViewController *loginVC;
#end
AppDelegate.m
#import "AppDelegate.h"
#import "LoginViewController.h"
#implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
// Override point for customization after application launch.
self.loginVC = [[LoginViewController alloc]initWithNibName:nil bundle:nil];
self.loginVC.title = #"Login Page";
self.navigationController = [[UINavigationController alloc]initWithRootViewController:self.loginVC];
self.window.rootViewController = self.navigationController;
[self.window makeKeyAndVisible];
}
LoginViewController.h
#import <UIKit/UIKit.h>
#import "MyProfileViewController.h"
#interface LoginViewController : UIViewController
#property (strong,nonatomic)MyProfileViewController *myProfileVC;
#end
Login button action in LoginViewController.m file
- (IBAction)pushMyProfileView:(id)sender
{
self.myProfileVC = [[MyProfileViewController alloc]initWithNibName:nil bundle:nil];
[self.navigationController pushViewController:self.myProfileVC animated:YES];
}
Basically you can achieve that by using:
Apple containers (UINavigationController, UITabbarController, UISplitController)
Containment API
Using "normal" view controller and modal presentation
Containment API is probably what you are looking for, you create a UIViewController that is responsible to manage the presentation of its child view controllers. Here is Apple Documentation, there are plenty of examples inside.
As a beginner I believe the easiest solution for you it to use a Storyboard and create a segue between your View Controller.
Inside your ViewController you should override prepareForSegue: method to pass data to the segue.destinationViewController

iOS dev - UINavigationController: send data backwards to 2nd parent view

so, I need to send data backwards when poping two views. I tried using protocol, so this is part of my code:
RootViewController.h
#import <UIKit/UIKit.h>
#import "ThirdViewController.h"
#class SecondViewController;
#interface RootViewController : UIViewController <PassInt>
#property (strong, nonatomic) SecondViewController *secondViewController;
#property (strong, nonatomic) ThirdViewController *thirdViewController;
#property (nonatomic) int intNumber;
#end
RootViewController.m
#import "RootViewController.h"
#import "SecondViewController.h"
#implementation RootViewController
#synthesize secondViewController = _secondViewController;
#synthesize thirdViewController = _thirdViewController;
#synthesize intNumber = _intNumber;
- (void)setIntNumber:(int)number{
_intNumber = number;
}
#pragma mark - View lifecycle
- (void)viewWillAppear:(BOOL)animated {
if(!_thirdViewController){
_thirdViewController = [[ThirdViewController alloc] initWithNibName:#"ThirdViewController" bundle:[NSBundle mainBundle]];
}
if(!_secondViewController){
_secondViewController = [[SecondViewController alloc] initWithNibName:#"SecondViewController" bundle:[NSBundle mainBundle]];
self.secondViewController.thirdViewController = self.thirdViewController;
}
[self.navigationController pushViewController:self.secondViewController animated:YES];
}
#end
SecondViewController.h
#import <UIKit/UIKit.h>
#class ThirdViewController;
#interface SecondViewController : UIViewController
#property (strong, nonatomic) ThirdViewController *thirdViewController;
#end
SecondViewController.m
#import "SecondViewController.h"
#import "ThirdViewController.h"
#implementation SecondViewController
#synthesize thirdViewController = _thirdViewController;
...
-(void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex{
[self.navigationController pushViewController:self.userPreferencesViewController animated:YES];
}
#end
ThirdViewController.h
#import <UIKit/UIKit.h>
#protocol PassInt <NSObject>
#required
- (void) setIntNumber:(int)number;
#end
#interface ThirdViewController : UIViewController{
id <PassInt> delegate;
}
#property (retain) id delegate;
- (IBAction)saveChanges;
#end
ThirdViewController.m
#import "ThirdViewController.h"
#implementation ThirdViewController
- (IBAction)saveChanges{
int someInt = 3;
[[self delegate] setIntNumber:someInt];
UINavigationController *tempNavigationController = self.navigationController;
[tempNavigationController popViewControllerAnimated:NO];
[tempNavigationController popViewControllerAnimated:NO];
}
...
#end
I would appreciate any help!
In the UINavigationController reference check the property call :
#property(nonatomic, copy) NSArray *viewControllers
Discussion
The root view controller is at index 0 in the array, the back view controller is at index n-2, and the top controller is at index n-1, where n is the number of items in the array.
That could give you a handle to the rootViewController.
Would that be a good solution for you?
There is other ways. But from your comment I think that could be a match.
[[self.navigationController viewControllers] objectAtIndex:0].someProerty;
Another method could be to use NSNotifications. Have the RootViewController resgister as an observer for a notification posted by the ThirdViewController. Then in the userInfo dictionary of the notification posted by the ThirdViewController, you pass someInt as an NSNumber.
This provides sufficient abstraction because your ThirdViewController doesn't need to know what kind of object requires the information, it is just posting it so interested observers know about it.
Good Luck
You're never assigning anything to the delegate member of your ThirdViewController in the code you posted. Also, delegates should usually be assign, not retain.

Why does my iOS app crash when trying presentModalViewController?

I've been banging my head against this all day, it seems like something simple but I can't figure it out.
I've got an iOS app that I created using the "View-based Application" template in XCode. Here is essentially the code I have:
AppDelegate.h:
#import <UIKit/UIKit.h>
#interface AppDelegate : NSObject <UIApplicationDelegate> {
UIWindow *window;
MainViewController *viewController;
}
#property (nonatomic, retain) IBOutlet UIWindow *window;
#property (nonatomic, retain) IBOutlet MainViewController *viewController;
#end
AppDelegate.m:
#import "AppDelegate.h"
#import "MainViewController.h"
#implementation AppDelegate
#synthesize window, viewController;
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
[self.window addSubview:viewController.view];
[self.window makeKeyAndVisible];
return YES;
}
- (void)dealloc {
[viewController release];
[window release];
[super dealloc];
}
#end
MainViewController.h:
#import <UIKit/UIKit.h>
#interface MainViewController : UIViewController {
}
-(IBAction) button:(id)sender;
#end
MainViewController.m:
#import "MainViewController.h"
#import "ModalViewController.h"
#implementation MainViewController
...
-(IBAction) button:(id)sender {
ModalViewController *mvc = [[[ModalViewController alloc] initWithNibName:NSStringFromClass([ModalViewController class]) bundle:nil] autorelease];
[self presentModalViewController:mvc animated:YES];
}
#end
There's nothing of interest in the ModalViewController.
So the modal view should display when the button is pressed. When I press the button, it hangs for a second then crashes back to the home screen with no error message.
I am stumped, please show me what I'm doing wrong!
There's nothing of interest in the ModalViewController.
Although there may not be anything of interest, there could still be something causing the problem.
Does your View Controller override the function loadView?
A problem that has got me a few times is if you don't call [super loadView]; first in your overriden loadView method. Not doing this causes a crash when moving into that View Controller.
Good luck in trying to solve this one!
N

Resources