Check which viewController is running in IPhone application Programmatically in Appdelegate - iphone

Is their any Possibilty to Check which viewController is running in IPhone application Programmatically in Appdelegate

There is no easy answer to this. You need to walk the view controller hierarchy starting with the main window's root view controller. If you encounter a UINavigationController you need to look at the topViewController. Once you get to a UIViewController, you need to look at the modalViewController, if any. If you have any tab bar controllers then you need to look at the currently selected tab.
Things like UISplitViewController complicates things since this can show two view controllers at once.
Here is the start of a category method you could add to UIViewController. This only handles regular view controllers and navigation controllers.
- (UIViewController *)topMostController {
if (self.modalViewController) {
return [self.modalViewController topMostController];
} else {
if ([self isKindOfClass:[UINavigationController class]]) {
UINavigationController *nc = (UINavigationController *)self;
return [nc.topViewController topMostController];
} else {
return self;
}
}
}
Call this from your app delegate on the key window's rootViewController.

Assuming you've set the rootViewController property in your AppDelegate:
[UIApplication sharedApplication].keyWindow.rootViewController;

For view controller it is not possible to get the curent running viewcontroller name.
for that you write one following method in your app delegate file & then call getCurentViewController method in each viewcontroller view did load or view did appear if you are not allocating agin by passing self to it
-(void) getCurentViewController:(UIViewController*) vc
{
if([vc isMemberOfClass:NSClassFromString(#"vcName")])
{
//write your code here
}
else if([vc isMemberOfClass:NSClassFromString(#"vcName1")])
{
//write your code here
}
}

UIViewController *currentViewController = yourRootViewController;
while (currentViewController.presentedViewController) {
currentViewController = currentViewController.presentedViewController;
}
//currentViewController is now your top-most viewController
//I use this same snippet in my production code

Related

Supporting Multiple Interface but have single interface in home screen not working in iOS8 + iPhone

I have view structure like below.
HomeView(Support only portrait mode)
|
|
V
View1(Support all orientation)
|
|
V
View2(Support all orientation)
Problem :
When i am coming back from View2(Landscape mode) to HomeView by calling popToRootViewController method,It did not call supportedInterfaceOrientationsForWindow method of App_Delegate and display
HomeView in landscape mode.
Image:
Note :
Same thing not happens when i came back from View1(Landscape mode) to HomeView by calling popToRootViewController method
it will call supportedInterfaceOrientationsForWindow and all works great.
If I run app using XCode6 in iOS7 all works great.
I read below question but it did not help me.
How to maintain presenting view controller's orientation when dismissing modal view controller?
In above link matt said that iOS8 stop support for friezing orientation, but I did not find it in apple document
if you have any reference link about this change please share.
Question :
1] Why delegate method supportedInterfaceOrientationsForWindow is not calling.
2] Is it possible to have one view with support single orientation and all other will support all orientation.
Thanks
I solve it and post answer as it will may help some one
Problem :
I have below code in supportedInterfaceOrientationsForWindow.
- (NSUInteger)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window
{
// Suport only portrait mode for home screen
if([self.navigationController.topViewController isKindOfClass:[ViewHome class]])
{
return UIInterfaceOrientationMaskPortrait;
}
return UIInterfaceOrientationMaskAll;
}
But delegate method supportedInterfaceOrientationsForWindow not called
when use popToRootViewControllerAnimated method when there ismore then two view Cotnrollersexists in stack.
Solution :
Step1: Create sub class of Navigation controller.
Step2: Override method popToRootViewControllerAnimated and write code as below
// Overwrite super class method popToRootViewControllerAnimated.
-(NSArray*)popToRootViewControllerAnimated:(BOOL)animated
{
// Only for iOS8 and above
if (floor(NSFoundationVersionNumber) > NSFoundationVersionNumber_iOS_7_1)
{
// Array which will contaimn all poped view controllers object.
NSMutableArray *popedControllersArray = [[NSMutableArray alloc] init];
// Tmp created controllers object
NSArray *controllers;
// Hold first view cotnrollers.
UIViewController *firstViewController = [self.viewControllers objectAtIndex:1];
// Pop to first view controllers with no animation.
controllers = [super popToViewController:firstViewController animated:NO];
// Add poped view cotnrollers objects to the array.
[popedControllersArray addObjectsFromArray:controllers];
// Pop to root view controller with animation
[super popViewControllerAnimated:YES];
// Add first view controller object as it is poped by above line.
[popedControllersArray addObject:firstViewController];
// return poped view controllers object.
return popedControllersArray;
}
else
{
// Called super view popToRootViewControllerAnimated method and return popped
// view controllers array.
return [super popToRootViewControllerAnimated:animated];
}
}
Please fill free for any comments and ask for any questions.

UIViewcontroller is not presented in correct orientation

I am presenting a view controller from another view controller using presentViewController.
The presenting view controller (The "SourceViewController") creates the new view controller and assigns it to a navigation controller before presentation (because the "NextViewController" wants a navigation bar and navigation controller).
// from the source view controller
#implementation SourceViewController
-(void)showNextViewController
{
NextViewController *viewController = [[NextViewController alloc] init];
UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:viewController];
[self presentViewController:viewController animated:YES];
}
#end
#implementation NextViewController
// in NextViewController
- (NSUInteger)supportedInterfaceOrientations {
return UIInterfaceOrientationPortrait;
}
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation
{
return UIInterfaceOrientationPortrait;
}
#end
But when I present the view controller when the originating view controller is in landscape the "NextViewController" isn't presented in portrait but rather in landscape like the source view controller.
I've tried many combinations of rotation methods but haven't been able to get it to present in the correct orientation.
I assume that it is possible because many apple components like UIImagePickerController are always presented in portrait , so how do I force its orientation?
Thanks
EDIT:
I've created a UINavigationController sub class:
PortraitNavigationController : UINavigationController
#implementation
-(BOOL)shouldAutorotate
{
return NO;
}
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation
{
return UIInterfaceOrientationPortrait;
}
#end
and then when presenting the NextViewController
PortraitNavigationController *nav = [PortraitNavigationController initWithRootViewController:nextViewController];
[self presentViewController:nav animated:YES];
and now NextViewController is indeed in portrait - but when I rotate the device to use this view controller and eventually dismiss it - the underlying source view controller looks all messed up.
The underlying view controller is a custom container view controller which is embedded in a UINavigationController
The containers it uses to display the child view controllers are not in their correct places
I don't want the container view controller to rotate at all as soon as the NextViewController is displayed and dismissed.
When you rotate your device the presented view controller is asked about the rotations and orientations it supports - In your case it's a UINavigationController and not an instance of NextViewController. One way to fix this is to subclass UINavigationController and override the rotation methods and forward the calls onto it's root view.
As a side not UIImagePickerController is a subclass of UINavigationController. It might make more sense to make NexViewController a subclass of UINavigationController and then inside that subclass initialize it with the correct root view controller.
Another option is to just alloc and init a UINavigationBar inside of NextViewController and add it as a subview if you don't need to use the navigation controller for anything. In this case autolayout comes in handy because you can pin it to the top, left, and right and let it figure out the correct size and location for it.

Getting Current ViewController Name in Parent ViewController

I have view controller as follows
parent view Controller
#interface Parent : UIViewController
{
}
child view Controller
#interface Child : Parent
{
}
Now i want current viewcontroller name in parent viewcontroller, I have searched but got simple clue is.
If it is a navigation based app, you can get the current view controller by,
UIViewController *currentVC = self.navigationController.visibleViewController;
But what is the currect procedure to access the current viewcontroller name in Parent Viewcontroller.
try this
for(UIViewController * view in self.navigationController.viewControllers)
{
if([view isKindOfClass:[Child class]])
{
//child VC is displayed on screen
}
}
Code below can help. I have not tried it but let me know if it worked
Write the following method in Parent class
-(void)getClassName:(NSString*)className{
NSLog(className);
//Your code here
}
Following lines where you need to access the current viewcontroller name
[self getClassName:NSStringFromClass([self class])];
Hope this post was helpful
I have founded the answer,
in Parent ViewController:
- (void)viewDidLoad
{
UIViewController *currentVC = self.navigationController.visibleViewController;
NSLog(#"The Current Class : %#", [self getClassName:currentVC]);
}
- (NSString*) getClassName:(id) obj
{
const char* className = class_getName([obj class]);
NSString *clsName = [#"" stringByAppendingFormat:#"%s",className];
return clsName;
}
When we are calling [super viewDidLoad] from Child ViewController then Parent ViewController was initialized, Here i am taking the class name of the current view controller. So In my Application i dont want to write this line of code in each view controller instead i have written in Parent View Controller.
Note: This work for navigation based app only, because we are getting current visibleViewController from navigationController

Using a Delegate with a TabBarController

I have a TabBarController which is set up with multiple ViewControllers at launch. When the user clicks a button I want to send them to a different ViewController in the TabBarController, and pass data through a delegate.
I have a protocol and delegate set up. However, when do you set the delegate since all the ViewControllers are in the TabBarController
Is this possible, how can I pass data to another ViewController in the TabBar when the user clicks a button. Any ideas, I'd really like to use a delegate.
- (IBAction)sendData:(id)sender
{
[self.delegate setStringData:strData];
self.tabBarController.selectedIndex = 0;
}
Edit:
So let's say I have a TabBarController with two ViewControllers called ViewControllerOne and ViewControllerTwo.
I have ViewControllerTwo set up as the delegate and protocol. This is the ViewController that will send data to ViewControllerOne after the button is pressed. ViewControllerOne implements protocol and contains the method setStringData which should be called after the button in ViewControllerTwo is pressed.
From a UIViewController you want to change the selected tab bar index and pass data.
I suggest you add a function in you app delegate for this.
That way your UIViewController won't be tied with a UITabBar (if tomorrow you want to use a different UI idiom, you will just have to change the implementation of your function in your app delegate).
To pass data, i you could try to introspection in your function : you take the current UIViewController of the new selected tab index, verify it responds to your selector and call the function.
Edit :
Let's assume your 'just' have to change the selected tabBar index (e.g. your UIViewController will always be the same on the new tab bar index).
In your first View Controller :
- (IBAction)sendData:(id)sender
{
UIApplicationDelegate * appDelegate = [[UIApplication sharedApplication] delegate];
if ([appDelegate respondToSelector:#selector(goToFirstTabBarWithData:)])
{
[appDelegate performSelector:#selector(goToFirstTabBarWithData:) withObject: strData];
}
}
In your Appdelegate :
- (void)goToFirstTabBarWithData:(NSString *)data
{
self.tabBarController.selectedIndex = 0;
UIViewController * vc = [self.tabBarController.viewControllers objectAtIndex:0];
if ([vc respondToSelector:#selector(setStringData:)])
{
[vc performSelector:#selector(setStringData:) withObject:data];
}
}
In your second View controller (the one you will arrive on) :
- (void)setStringData:(NSString *)data
{
// Do something...
}
I found a simpler solution to my problem. Inside of ViewControllerTwo, I just create an instance of ViewControllerOne and pass it that data I need. Then I change the tabBarController index to ViewControllerOne.
For example:
// A method inside of ViewControllerTwo
ViewController *viewcontrollerOne = [ViewcontrollerOne alloc] init];
[viewcontrollerOne setStringData:str];
[viewcontrollerOne release];
self.tabBarController.selectedIndex = 0;

How to enumerate view controllers on iPhone?

I have a modal view controller which fetches a password. Since I don't want the password written to disk if my application is interrupted, I want to cear the password on applicationWillResignActive. (For those who may comment, I know the secure text field does not properly zeroize).
I've tried the following code, and my view controller is never located. For the first set of code (UIView) I believe its because I'm mixing and matching views and view controllers. I'm not sure why the second set of code (UIViewController) is not working since a few folks have suggested it.
How does one enumerate view controllers and locate a controller of interest? I simply want to send clearPassworAndPin to PasswordPromptController if present (since viewWillDisappear is not always sent when the view disappears).
Modified 7KV7 and Jhaliya answer is below (it worked). The 'if' statement using viewController.modalViewController was executed 5 times (once for each controller in the tab view). So the single modal controller of interest was sent the clearPasswords message 5 times.
for (UIViewController * viewController in viewsControllers)
{
if ([viewController isKindOfClass:passwordPromptClass])
{
[(PasswordPromptController *)viewController clearPassworAndPin];
}
else
{
if(viewController.modalViewController)
[self clearPasswords:[NSArray arrayWithObjects:viewController.modalViewController, nil]];
}
}
Using UIViews (no joy)
- (void)applicationWillResignActive:(UIApplication *)application
{
if(application.windows != nil)
[self clearPasswords:application.windows];
}
- (void)clearPasswords:(NSArray *)subviews
{
Class passwordPromptClass = [PasswordPromptController class];
for (UIView * subview in subviews)
{
if ([subview isKindOfClass:passwordPromptClass])
[(PasswordPromptController *)subview clearPassworAndPin];
}
}
Using UIViewController (no joy)
- (void)applicationWillResignActive:(UIApplication *)application
{
if(tabBarController.viewControllers != nil)
[self clearPasswords:tabBarController.viewControllers];
}
- (void)clearPasswords:(NSArray *)viewsControllers
{
Class passwordPromptClass = [PasswordPromptController class];
for (UIViewController * viewController in viewsControllers)
{
if ([viewController isKindOfClass:passwordPromptClass])
[(PasswordPromptController *)viewController clearPassworAndPin];
}
}
NSArray *array = [self.navigationController viewControllers];
yourViewController = [array objectAtIndex:yourChoiceOfIndex];
Hope it helps.
At the point where you present the PasswordPromptController as a modalViewController could you not store it as an instance variable? Then, in your applicationWillResignActive: callback you will have a handle to the VC to message against.
Be sure to release and nullify your reference to the PasswordPromptController reference when it gets dismissed.
you will have to go through the navigation stack to get the controllers.
Use UINavgationController below method to get all viewController in your navigation stack.
#property(nonatomic, copy) NSArray *viewControllers
hmm..., I have to say I like to give alternative suggestions/solutions as many folks have tried to answer you question specifically.
If you found it's not easy to find the PasswordPromptController by enumerating view controllers, you can just declare (alloc/init) that controller in your app delegate, whenever you need to use it in other controllers, get it through app delegate, do something like presenting as a modal view.
When you want to do something against it in your app delegate, e.g. clear the pwd, it's super easy because you have the reference to it.