Short hand for [[UIApplication sharedApplication] delegate]? - iphone

I stored global variables in my AppDelegate and access them by:
AppDelegate *d = [[UIApplication sharedApplication] delegate];
d.someString = ...
What's the recommend way to save some typing and so I don't need to AppDelegate *d = [[UIApplication sharedApplication] delegate]; again and again? Thanks!

As Shaggy Frog said, define a macro in your YourAppDelegate.h file, an example like this:
#define AppDelegate (YourAppDelegate *)[[UIApplication sharedApplication] delegate]
Then you can get the app delegate in your code like this:
[AppDelegate ......];

Since your app delegate never really changes, you can create an external that you define in the app delegate code, very similar to the NSApp external for Mac OS X Cocoa applications.
So, define the external in your AppDelegate header (or something else that you would include everywhere):
extern AppDelegate* appDelegate;
Then create it and set it in your implementation file:
AppDelegate* appDelegate = nil;
// later -- i can't recall the actual method name, but you get the idea
- (BOOL)applicationDidFinishLaunchingWithOptions:(NSDictionary*)options
{
appDelegate = self;
// do other stuff
return YES;
}
Then other classes can just access it:
#import "AppDelegate.h"
// later
- (void)doSomethingGreat
{
NSDictionary* mySettings = [appDelegate settings];
if( [[mySettings objectForKey:#"stupidOptionSet"] boolValue] ) {
// do something stupid
}
}

You could just create a C-style macro and put it in a header file somewhere.
(As for using your app delegate as a giant global variable catch-all, that's another rant for another day.)

I create a category called UIApplication+delegate with some convenience messages in it. Getting my specific delegate being one of the convenience messages. So, for instance, if my app delegate was called MyAppDelegate, it would look like this:
UIApplication+delegate.h
#import "MyAppDelegate.h"
#interface UIApplication(delegate)
+ (MyAppDelegate *)thisApp;
#end
and UIApplication+delegate.m
#import "UIApplication+delegate.h"
#implementation UIApplication(delegate)
+ (MyAppDelegate *)thisApp {
return (MyAppDelegate*)[[UIApplication sharedApplication] delegate];
}
#end
In a class that needs the delegate, I do this:
#import "UIApplication+delegate.h"
...
- (void)doStuff {
MyAppDelegate *app = [UIApplication thisApp];
// use "app"
}

I also created a category, except that I applied mine to NSObject so any object in the application can easily get to the delegate.
#import "MyAppDelegate.h"
#interface NSObject(delegate)
- (MyAppDelegate *) appDelegate;
#end
#import "NSObject+delegate.h"
#implementation UIApplication(delegate)
- (MyAppDelegate *)appDelegate {
return (MyAppDelegate *)[[UIApplication sharedApplication] delegate];
}
#end

Related

How can I call the one method in all the view controllers?

How can I call the one method in all the view controllers?
One method in viewcontroller1 like,
- (void)doSearch
{
NSLog(#"Search..!");
}
I want to call doSearch method from viewcontroller2, viewcontroller3, viewcontroller4, viewcontroller5, etc.
How to do this?
You can declare it in separate class and instantiate that class in all viewControllers, or you could define this method in your AppDelegate and call in all your viewController. you could access the AppDelegate in your ViewControllers by getting its instance like this
self.appDelegate=(AppDelegate*)[[UIApplication sharedApplication]delegate];
and finally call the method like this
[self.appDelegate doSearch];
Generally it is preferable to declare all your methods or data which is shared through the application in a separate class and use this class. I usually use singelton Object class in my application, define all the shared data in that and finally access in all classes
here is example of singelton class
MyData.h
#interface MyData : NSObject
+(MyData*)getInstance;
-(void)search;
#end
MyData.m
#import "MyData.h"
#implementation MyData
static MyData *instance =nil;
+(MyData *)getInstance
{
#synchronized(self)
{
if(instance==nil)
{
instance= [[MyData alloc]init];
}
}
return instance;
}
-(void)search {
NSLog(#"search");
}
#end
finally in your viewController
MyData *myData=[MyData getInstance];
[myData search];
You can declare this method in AppDelegate.h. like
- (void)doSearch;
And Implement it in AppDelegate.m like
- (void)doSearch
{
//Your Search Logic
}
Then, Create AppDelegate instance like
appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
Make Your Project's .pch file look like following:
#ifdef __OBJC__
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
#import "AppDelegate.h"
AppDelegate *appDelegate;
#endif
Now, From Any ViewController, You can call method like:
[appDelegate doSearch];
Happy Coding.
NOTE: Personally, I avoid this kind of implementation in AppDelegate Class.
I use Singleton Object Pattern for this kind of purpose. But, Given is the quickest way.
___________EDIT____________
Add a New Class file of NSObject type: Name it CommonMethod (or whatever you want)
in CommonMethod.h
#interface CommonMethods : NSObject
+ (CommonMethods *)sharedObject;
+ (void)doSearch;
in CommonMethod.m
#import "CommonMethods.h"
#implementation CommonMethods
+ (CommonMethods *)sharedObject
{
static dispatch_once_t once;
static CommonMethods *sharedObject;
dispatch_once(&once, ^ { sharedObject = [[CommonMethods alloc] init]; });
return sharedObject;
}
+ (BOOL)doSearch
{
// Your Search Logic.
}
Now, Add #import "CommonMethods.h" to your project's .pch file.
And You are all set to go...!!!
Method Call (in any of your viewController): [CommonMethods doSearch];
Put all controllers in an NSArray *, lets say it is called controllerArray.
Then you can make all controllers perform selector with:
[controllerArray makeObjectsPerformSelector:#selector(doSearch)];
Add your method to AppDelegate.m file
- (void)doSearch
{
NSLog(#"Search..!");
}
And Add #import "AppDelegate.h" In UIViewController that you want to call :
You can call method by,
AppDelegate *del = (AppDelegate *)[[UIApplication sharedApplication] delegate];
[del performSelector:#selector(doSearch) withObject:nil afterDelay:0];
From Any UIViewController
You may like to read below tutorial
Global functions and variables in Objective C
or You can create methods in the appDelegate class that you can access through all your app. For example, in your AppDelegate.h you have declared this method as follow:
-(void)myMethod;
In your AppDelegate.m, you define it as:
-(void)myMethod
{
NSLog(#"myMethod is getting called");
}
From any other classes (Master or Detail, etc.), you access myMethod by:
#import "AppDelegate.h"
AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
[appDelegate myMethod];
The best way to make AbstractViewController and inside it add all your common behaviors or methods. Any ViewController will inherits from the Abstract and can call any common Method
The best way is to make a separate header file make this method a class method and you can call this anywhere in the project by importing the class.And you can include this class into your pch file so that import can be avoided from all VCs
class.h
+ (void)doSearch
{
NSLog(#"Search..!");
}
in ViewControllers
#import "class.h"
-(void)someMethod
{
[class doSearch];
}

How to access an object that has been initialized in the ApplicationDelegate?

I need to initialize an object of an object in my AppDelegate at startup. Whenever I try to access the ivar somewhere else all that is returned is null.
What I'm doing can be simplified as
//AppDelegate.h:
#interface AppDelegate : UIResponder <UIApplicationDelegate> {
NSString* someString;
}
#property (nonatomic, copy) NSString* someString;
and then in the AppDelegate.m
//AppDelegate.m
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
someString = #"Hello World!";
NSLog(#"%#",someString);
}
This is what I do when I access the NSString-object
//ViewController.m
- (void)viewDidLoad {
[super viewDidLoad];
AppDelegate *delegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
NSLog(#"%#",delegate.someString);
}
The output text is
2012-09-30 22:26:45.125 Labor3[22524:f803] Hello World!
2012-09-30 22:26:45.127 Labor3[22524:f803] (null)
without any warnings or errors.
The problem I'm having is a bit more complicated but the essentials stay the same and I can't even get the above example to work. Any hint is appreciated.
Add
#synthesize someString;
After
#implementation AppDelegate
in your app-delegate .m file.
You should use _someString instead of someString or use Andrey's answer solution, in your code property someString and ivar someString haven't any connection

iPhone: How do I share information between my UITabBarViewController and the individual Tabs?

I have a TableViewController that segues into a TabBarViewController.
I know how to pass my object via a segue, but not by a relationship like the TabBarViewController and it's tab share.
How can I do this? From the TabView is there a way to access the TabBarViewControllers member variables?
Update:
This is how I've solved the problem so far, but I'm not crazy about using the AppDelegate to do this...
Add the Following to WhateverYouNamedYourAppDelegate.h
#class myObjectIWantToPass;
#property (strong, nonatomic) myObjectIWantToPass *object;
Then add the following to the View Class file you have your data in that you want to pass on. I'm going to assume you know how to set up your object already in this file if your planning on passing it to another view.
WhateverYouNamedYourAppDelegate *appDelegate =
(WhateverYouNamedYourAppDelegate *)[[UIApplication sharedApplication] delegate];
appDelegate.object = object;
Then you do some similar work to retrieve the object back from the appDelegate in your destination View Class.
WhateverYouNamedYourAppDelegate *appDelegate = (WhateverYouNamedYourAppDelegate *)[[UIApplication sharedApplication] delegate];
object = appDelegate.object;
You can make singleton classes, so that all of the controllers can access those variables in the Singleton. See Code below
SingletonClass.h
#interface SingletonClass : NSObject {
NSString *someString;
}
#property(nonatomic, retain)NSString *someString;
+(id)shared;
#end
SingletonClass.m
#import "SingletonClass.h"
static SingletonClass *aShared;
#implementation LibShared
#synthesize someString;
+(id)shared
{
if (aShared == nil) {
aShared = [[self alloc] init];
}
return aShared;
}
-(id)init
{
if (self = [super init]) {
}
}
-(void)dealloc
{
[someString releease];
[super dealloc];
}
In the tabbar you can set the variable on SingletonClass:
[[SingletonClass shared] setSomeString:#"Value_Set"];
On the tableViewController, you can get the property of the someString variable on the SingletonClass:
NSString *string = [[SingletonClass shared] someString];
There's no need for a singleton pattern here. Instead, you can send the data-object forwards in - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender just as you do normally, you just need to find the correct viewController in the UITabBarController's viewControllers property.
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqualToString:#"MyTabBarSegue]) {
UITabBarController *tabBarController = segue.destinationViewController;
// Either set the index here, if you know for sure which viewController is which, or
// Enumerate the viewControllers for isKindOfClass:[MYCustomViewController class] to be robust and change-proof
MYCustomViewController *myVC = [[tabBarController viewControllers] objectAtIndex:0];
myVC.dataObject = self.dataObject;
}
}

Does categories allow to use dot syntax when accessing chained methods?

I need to attach a method to all my UIViewControllers. The method just returns a pointer to my main app delegate class object. However, xcode 4 throws an error "parse issue expected a type" in header file at the declaration of output parameter type MyAppDelegate. If I change it to the other type, for example id, then the error goes away. But I'm using a dot syntax to access main app delegate properties and if I will change the type to id then xcode4 not recognize my main app delegate properties. I have included the definition file of category to those UIViewController class files where I'm accessing this method. Here is definition of my category:
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
#import "MyAppDelegate.h"
#interface UIViewController (MyCategory)
-(MyAppDelegate *) appDelegate; // xcode 4 complains about MyAppDelegate type, though it autocompletes it and show even in green color.
#end
Here is an implementation:
#import "MyCategory.h"
#implementation UIViewController (MyCategory)
-(MyAppDelegate *)appDelegate{
MyAppDelegate *delegate = (MyAppDelegate *)[[UIApplication sharedApplication] delegate];
return delegate;
}
EDIT: The reason why I'm implementing this category is that I need to have handy shortcut for accessing my main app delegate from any place of the code (in my case from UIViewControler objects):
// handy shortcut :)
self.appDelegate.someMethod;
//not so handy shortcut :(
MyAppDelegate *delegate = (MyAppDelegate *)[[UIApplication sharedApplication] delegate];
I think you have a dependency cycle in your header files. If MyAppDelegate.h imports MyCategory.h either directly or indirectly, the first time the category declaration is compiled the compiler won't know what a MyAppDelegate is. You should remove the import of MyAppDelegate.h from the MyCategory.h header and replace it with a forward class declaration:
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
#class MyAppDelegate
#interface UIViewController (MyCategory)
-(MyAppDelegate *) appDelegate;
#end
Then put the import in the .m file instead. This is actually a good general principle. Where possible, use forward class declarations in the headers and put imports in the implementation file.
-(id)appDelegate{
return [[UIApplication sharedApplication] delegate];
}
//Calling code
MyAppDelegate* delegate = (MyAppDelegate*)[self appDelegate];
Add #class MyAppDelegate; to the top of your category header to let the compiler know that this class exists or #import its header.
Generally, it might be a better idea to have a class method in MyAppDelegate that does the same thing. Conceptually, appDelegate is not a property of an individual view controller which your method implies.

need to define a "modifiable" global variable in objective-c

I have the following issue. I have two classes that manipulate information but they are completely disconnected, i.e. I can't reach the other class.
I need both classes to use a certain value. For example, class A sets the value foo = A and class B needs to be able to read that value and rest foo to nil.
I thought about creating the variable in the main app delegate, but can't figure out how.
Ideas?!!
Global variables are generally bad idea. Based on your description i think you can use KVO to inform class B about the changes in 'foo'.
But if you relly need a global variable you can do this:
#interface YourAppDelegate : NSObject <UIApplicationDelegate> {
}
#property (nonatomic) NSString *foo;
#end
#implementation YourAppDelegate
#synthesize foo;
...
#end
#implementation ClassA
...
- (void)someMethod {
YourAppDelegate *appDelegate = (YourAppDelegate *)[[UIApplication sharedApplication] delegate];
appDelegate.foo = #"NewValueOfFoo";
}
...
#end
#implementation ClassB
...
- (void)otherMethod {
YourAppDelegate *appDelegate = (YourAppDelegate *)[[UIApplication sharedApplication] delegate];
NSLog(#"Value of foo: %#", appDelegate.foo); //This will print: "Value of foo: NewValueOfFoo"
}
...
#end
I'm not sure what you mean by "completely disconnected". Depending on what you're trying to do, you could use NSUserDefaults
http://developer.apple.com/library/ios/#documentation/cocoa/reference/foundation/Classes/NSUserDefaults_Class/Reference/Reference.html
or NSNotifications
http://developer.apple.com/library/ios/#documentation/Cocoa/Reference/Foundation/Classes/NSNotification_Class/Reference/Reference.html
If class A doesn't need to know about class B, you could consider delegation as well.
Why can't he just do this?
A. Add 2 new files to your project: GlobalValues.h and GloblaValues.m.
B. Open GlobalValues.h, and declare all your needed variables.
extern NSString *MyServiceName; // name of the 'service':
C. Open GlobalValues.m, and start the new file by importing GlobalValues.h, and assign values to the variables you declared in the header file:
#import "GlobalValues.h"
NSString *MyServiceName = #"MyService is called THIS";
D. In the implementation files of the classes that need to use these variables, you would put - at the very beginning:
#import "GlobalValues.h"