This question already has answers here:
iOS - Calling App Delegate method from ViewController
(13 answers)
Closed 6 years ago.
I know there are duplicates of this question but my situation is different here.
When user goes back to the home (void)applicationDidEnterBackground gets invoked from the AppDelegate class. However once user presses home button, I don't want user to see this view controller again, so I have a method named (void)goToBeginning that switches to another view controller. I want to be able to call this method from AppDelegate. I don't really want to use NotificationCenter for this. Also the picked solution here:
Calling view controller method from app delegate
does not work for me as it initialises new object whereas I want to be able to call an object that is already in the view. How can I do that? I am using iOS 7 and XCode 5.
Notification. But you don't want this.
You can get the reference to your that viewController in the AppDelegate. Than call that (void)goToBeginning method in the (void)applicationDidEnterBackground
For example: In your ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
appDelegate.myViewController = self;
}
And in your AppDelegate:
#class MyViewController;
#interface AppDelegate : UIResponder <UIApplicationDelegate>
#property (weak, nonatomic) MyViewController *myViewController;
#end
And in the AppDelegate's implementation:
- (void)applicationDidEnterBackground:(UIApplication *)application
{
[self.myViewController goToBeginning];
}
Related
I have a class declaration which contains an singleton object that manages the data (called sharedDatacontroller).
Now there are many other screen and declaration is the last one. I have to check if the user moves back from declaration screen and alters any data , then have to reset a switch button on the declaration screen.
My Approach:
-(void) viewWillDisappear:(BOOL)animated
{
self.sharedControllerClone=sharedController;
}
-(void) viewWillAppear:(BOOL)animated
{
if ([self.sharedControllerClone isEqual:sharedController])
{
NSLog(#"Not Same");
self.acceptDeclarationSwitch.on= self.acceptDeclarationSwitch.on;
}
else
{
self.acceptDeclarationSwitch.on= !self.acceptDeclarationSwitch.on;
}
}
But when the control comes in after navigating from back screen , the self.sharedControllerClone is reseting to Nil. How to preserve its state..any ideas?
Hope I am clear this time.
You can try this thing by creating Macros in your AppDelegate and assigning different states to a property taken in AppDelegate so that you will come to know that what is your current state. You can create an object of your AppDelegate in your required controllers and in their ViewDidLoad, you can assign the current state to AppDelegate like this:
//in AppDelegate
#import <UIKit/UIKit.h>
#define FIRST_CONTROLLER 1
#define SECOND_CONTROLLER 2
#define THIRD_CONTROLLER 3
#interface AppDelegate : UIResponder <UIApplicationDelegate>
#property (strong, nonatomic) UIWindow *window;
#property int previousControllerState;
#end
And then, you can set your previousControllerState in the ViewDidLoad of your required controller.
//in your ViewControllers
- (void)viewDidLoad
{
[super viewDidLoad];
app.previousControllerState = FIRST_CONTROLLER;
}
And you can check your state in if condition in the next controller.
You have to take the states in AppDelegate to prevent the objects from getting nil. Otherwise, as soon as you move from one controller to another, the object of the previous controller might be getting nil.
I have an application i am making but here is the problem which i been spedning hours figuring out.
I have a Tab-Based app, The first tab has a UILabel Object which should display an NSString from the SecondViewController.m which has a Method:
-(IBAction) save: (id) sender{
// This String holds data from the secondViewController's textfield to be passed to the
// UILabel whch is on the firsViewController.m
NSString *data = self.addDataTextfield.text;
}
I have used many methods including Singletons but they dont work as i have read somewhere that singletons are meant to pass data from Parent to child and child cant send data to the parent controller in this case BUT the Only way would be to use Protocols which i am but i am kind of lost using this method. Here is what i have on my secondViewController.h
#import <UIKit/UIKit.h>
#import "singletonObj.h"
#import "AppDelegate.h"
// Using a Protocol to pass data Back to the parent view
#protocol passStringDelegate <NSObject>
-(void) enteredString: (NSString *)string;
#end
#interface SecondViewController : UIViewController <UITextFieldDelegate>
{
singletonObj *object; // This singleton isnt being used, Just there incase
}
#property (strong, nonatomic)IBOutlet UITextField*addDataTextField;
- (IBAction)Save:(id)sender;
#property (retain) id <passStringDelegate> delegate;
#end
SO my Question is, is there any way i cando this and pass data from this secondViewController using #protocol or at least can anyone show me how to Use NSNotificationCenter within this code to pass data ? i dont feel comftarble using the AppDelegate class to pass data as it seems to go against apple's way or prepareforSegue which doesnt work for me.
I been searching around but most i find do the data being sent from the parent to the child but i dont see Tabbed based examples where the ChildViewController can send an NSString to the ParentViewController to display that data on an UILAbel.
There are several ways to do this. From any of the tab bar controller's content controllers, you can access another of the controllers with something like self.tabBarController.viewControllers[0]. This will reference the controller in the first tab. So, if you want to pass a string back to the first controller from the second, create a string property in the first controller (say, passedInString), and in the second controller, have something like this:
FirstViewController *first = self.tabBarController.viewControllers[0];
first.passedInString = self.stringToPass;
Ok #user2994008, in a UITabBarController app setup, I would not use a delegation pattern at forces coupling between the child view controllers in some manner. Posting a notification will get the job done, the only problem is what should trigger the notification to be posted. In this case, a quick and dirty way is to just post the notification in viewWillDisapper: as that will get called when the user switches tabs.
SecondViewController.m
//SecondViewController.m
//this is the view with the UITextField in it
#import "SecondViewController.h
#implementation SecondViewController
- (void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
NSLog(#"%s", __FUNCTION__);
//since this gets called when the user switches tabs, i'll post the
//notification from this method
//retrieve our text field's text and store it in a dictionary
NSDictionary *dict = #{"text":self.addDataTextField.text};
//add the dictionary as userInfo: and post notification
[[NSNotificationCenter defaultCenter] postNotificationName:#"myAwesomeNotification" object:nil userInfo:dict];
}
//all other second view controller methods here
#end
FirstViewController.m
//FirstViewController.m
#import "FirstViewController.h"
#implementation FirstViewController
-(void)viewDidLoad {
[super viewDidLoad];
//add an observer for the notification and tell it what method to call when it gets the notification
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(actionTriggeredByNotification:) name:#"myAwesomeNotification" object:nil];
}
- (void)actionTriggeredByNotification:(NSNotification*)notification {
NSLog(#"%s", __FUNCTION__);
NSDictionary *userInfo = [notification userInfo];
NSString *data = userInfo[#"text"];
NSLog(#"Text data is: %#", data);
}
- (void)dealloc {
//be sure to remove observer
[[NSNotificationCenter defaultCenter] removeObserver:self];
//if using ARC, don't call super dealloc
}
//all other first view controller methods
#end
Also, drop the singleton stuff trying to pass data that way. That gets into trying to create what are in essence global variables and you don't really want that for passing simple strings around.
And while using notifications work ok here, some other solutions could be implemented using key-value observing (KVO) or adhering to the UITextFieldDelegate protocol and sending a message from one of those delegate methods. Even so, all these techniques still open up questions about when you actually want to retrieve the textfield's text.
Once you get your bearings, I'd HIGHLY recommend looking into ReactiveCocoa. It's a library designed specifically for solving problems like yours.
This a issue that have took me down since I am not able to solve it although it seems so easy.
The fact is that I have an iOS app, mainly a webview that loads a website, and I need to load different wen page when notification is received. I am implementing push notification and I have managed to get them working. They are received by the app in the App Delegate and then is when the problem starts. I would like to launch the webview with a specific URL but I don't know how to do it. I have tried to get the webview instance and passes the URL to it:
"SomeAppDelegate.h"
#import <UIKit/UIKit.h>
#class BrowserViewController;
#interface SomeAppDelegate : UIResponder <UIApplicationDelegate>
#property(nonatomic, retain) IBOutlet BrowserViewController *viewController;
#property (strong, nonatomic) UIWindow *window;
#end
"SomeAppDelegate.m"
#import "SomeAppDelegate.h"
#import "BrowserViewController.h"
#implementation SomeAppDelegate
#synthesize window = _window;
#synthesize viewController;
.........
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo
{
[viewController.webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:#"http://www.google.com"] cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:20]];
[self.window addSubview:viewController.webView];
[self.window makeKeyAndVisible];
Another test was to create an instance method within BrowserViewContrller trying to reload from there. I also tried to load story board programatically but when "Is Initial View Controller" is unchecked in storyboard the app crashes just before launch.
I did a lot of googling but I don't understand pretty much how this life cycle works. I will thank any help.
Probably, you should set your viewcontroller as AppDelegate's window.rootViewController in the didFinishLaunching:withOptions: method of your app delegate instead of adding it's webView as window subview - because webView is only loaded after UIViewController's method viewDidLoad got called - that means that your webView might not be loaded when you're trying to reload it with request.
I'm struggling getting started with the Universal App template in Xcode 4.1. I'm following the basic principles set out by kotancode here. The problem is getting the relevant view controller to load. I will focus on the iPhone part as an example. I create a subclass of UIViewController without a XIB as my "master" view controller class (where shared code will go). I then subclass this to create the iPhone specific UIViewController class called BaseViewController_iPhone, this time with a XIB.
The iPhone specific app delegate the header is set to:
#import "TestAppDelegate.h"
#import "BaseViewController_iPhone.h"
#interface TestAppDelegate_iPhone : TestAppDelegate {
BaseViewController_iPhone *viewController;
}
#property (nonatomic, retain) IBOutlet BaseViewController_iPhone *viewController;
#end
and for the implementation I try to override the applicationdidfinishlaunchingwithoptions method.
#import "TestAppDelegate_iPhone.h"
#implementation TestAppDelegate_iPhone
#synthesize viewController;
-(BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
[self.window addSubview:viewController.view];
[self.window makeKeyAndVisible];
return YES;
}
-(void)dealloc {
[viewController release];
[super dealloc];
}
#end
This doesn't appear to work, it compiles fine and runs, but the new view controller and the corresponding XIB are not displayed (the original main window xib from the template is). I'm sure i'm missing something very simple, but i've spent a long time googling to no avail. Any help gratefully received.
Thank you.
Have you connected the ViewController in the app's delegate's XIB to your "BaseViewController_iPhone *viewController" ?
Are you sure the ViewController in the app's delegate's XIB is of the type BaseViewController?
Is the ViewController loading the correct XIB (check that in the app's delegate's xib)?
Check that and give some feedback.
I think that I am a bit confused about iOS #property getter and setters. I am trying to set an NSString iVar in my AppDelegate.h file from another class so that it can be used by all of the classes in the project?
For example, I am working on an iPhone project that stores an iVar NSString *currentUser in AppDelegate.h. I need to be able to set this through one method in a ViewController.m and then get it through another method in a second ViewController?
Maybe Getter and Setter is the wrong direction of attack all together? I understand that i don't want to alloc init the AppDelegate as the iVar will only exist in that object and I want it accessible to ALL objects in ALL classes?
Please someone set me straight.
All the best,
Darren
Here's the setup for the app delegate.
#interface AppDelegate
{
NSString *__currentUser;
}
#property (monatomic, copy) NSString* currentUser;
#end
#implementation AppDelegate
#synthesize currentUser = __currentUser;
- (void) dealloc
{
[__currentUser release];
[super dealloc];
}
#end
From one view controller, you could set a value for the current user, and from a subsequent view controller, get that value for some nefarious purpose.
#implementation LoginController
- (void) viewDidLoad
{
...
AppDelegate *bob = [[UIApplication sharedApplication] delegate];
[bob setCurrentUser: #"Jim Kirk"];
...
}
#end
In some other view controller that appears later, the value of the current user can be accessed.
#implementation ProfileViewController
- (void) viewDidLoad
{
...
AppDelegate *bob = (AppDelegate *)[[UIApplication sharedApplication] delegate];
NSString * user = [bob currentUser];
// insert nefarious purpose for current user value here
...
}
#end