1

I need access to my core data managed object context often, and instead of getting an instance of the [[UIApplication sharedApplication] delegate] and storing it in a variable every time in every class, I was wondering if it would be ok to do this:

@interface NSObject(DelegateExtension)
- (AppDelegate*)appDelegate;
@end

@implementation 
NSObject(DelegateExtension)
- (AppDelegate*)appDelegate
{
    return (AppDelegate*)[[UIApplication sharedApplication] delegate];
}
@end

so then I can just do self.appDelegate anywhere in my code.

Is anything wrong with doing this that might night be obvious? Is it bad programming practice?

Snowman
  • 31,411
  • 46
  • 180
  • 303
  • possible duplicate of [Categories on NSObject -- keeping it safe](http://stackoverflow.com/questions/6693646/categories-on-nsobject-keeping-it-safe) – CodaFi May 01 '12 at 03:37

4 Answers4

5

Alternatively, you could add a preprocessor macro (or a static C function) to your Prefix.pch file:

#define AppDelegateInstance() (AppDelegate *)[[UIApplication sharedApplication] delegate]

This will make your app delegate accessible from anywhere in your code, and there is no chance of conflicting with any existing methods named appDelegate.

Cameron Spickert
  • 5,190
  • 1
  • 27
  • 34
  • To use, you would just type `AppDelegateInstance()` anywhere you want to access the app delegate instance. The preprocessor will substitute it with `(AppDelegate *)[[UIApplication sharedApplication] delegate]` before compiling. – Cameron Spickert May 01 '12 at 03:54
  • But could you still access properties with a macro, I wonder? – CodaFi May 01 '12 at 03:58
  • Yes. If your app delegate has a property named `foo`, you should still be able to access it using `[AppDelegateInstance() foo]`, which will expand to `[(AppDelegate *)[[UIApplication sharedApplication] delegate] foo]`. – Cameron Spickert May 01 '12 at 03:59
  • 1
    Excellent, +1. I would have gone with a constants header file, but the prefix seems more appropriate and efficient. – CodaFi May 01 '12 at 04:00
  • @CameronSpickert : this method works fine.. Consider if we have to change value for the appdelegate property foo, how to do that..? – Mano Oct 18 '13 at 10:31
  • @ManojEllappan `[AppDelegate() setFoo:@"newFoo"];` – Cameron Spickert Oct 22 '13 at 05:18
2

NSObject doesn't have any meaningful connection to UIApplication or its delegate. From a design standpoint, I think doing this would be a hack in the bad sense. There are three other solutions that I can come up with off the top of my head that I think would be millions of times better:

  1. Function, whose declaration is in a header which is imported by your prefix header.

  2. Category on UIApplication, which is actually a class that has something to do with the action you're trying to take.

  3. Global pointer, like NSApp on OS X*, that's set up as the first thing in your program to point to the UIApplication instance.

  4. (Four solutions!) Global pointer to the app delegate.

See On lazy instantiation and convenience methods for info on implementing 3 or 4.


*Really don't understand why they didn't do this on iOS.

Community
  • 1
  • 1
jscs
  • 63,694
  • 13
  • 151
  • 195
  • @mohabitar: I've added a link to an answer of mine that I think will give you the idea. Let me know if you need more info and I'll expand. Interesting question, btw. – jscs May 01 '12 at 04:13
2

I usually use a global variable to point to the app delegate.

In MyAppDelegate.h:

extern MyAppDelegate* AppDelegate;

In MyAppDelegate.m:

MyAppDelegate* AppDelegate = nil;

- (id)init {
    if (self = [super init]) {
        AppDelegate = self;
        …
    }
}

Now anyone who imports "MyAppDelegate.h" can use the AppDelegate variable to access your app delegate.

Darren
  • 25,520
  • 5
  • 61
  • 71
  • Oh nice..what effect would adding `static` to the declaration have? – Snowman May 01 '12 at 04:17
  • `static` limits the visibility to the file in which the declaration is made -- it would be contrary to your needs. – jscs May 01 '12 at 04:18
  • I'm getting this error: `Undefined symbols for architecture i386: "_appDelegate", referenced from: -[AppDelegate application:didFinishLaunchingWithOptions:] in AppDelegate.o` – Snowman May 01 '12 at 04:27
  • I set appDelegate = self in applicationDidFinishLaunching – Snowman May 01 '12 at 04:27
  • Do you have `AppDelegate* appDelegate = nil;` in your AppDelegate.m file? – Darren May 01 '12 at 04:30
  • Weird, I overrided the init method of AppDelegate and put a NSLog statement in there, and it showed up twice. Any idea why that would happen? – Snowman May 01 '12 at 04:33
  • 1
    Set a breakpoint. If it's really being called twice the stack trace will tell you why. – Darren May 01 '12 at 04:41
  • I'm not that familiar with the debugger, but I hit the "step over" button several times, and it repeated the execution of init in the AppDelegate class.. – Snowman May 01 '12 at 04:45
  • I commented out **everything** in my AppDelegate.m, so nothing occurs in the entire execution of the app except the init method, and it **still** gets called twice.. – Snowman May 01 '12 at 05:00
  • Turns out I had an AppDelegate object in one of my XIBs – Snowman May 01 '12 at 05:14
0

Of course it's safe, so long as you know that apple doesn't or won't have a method named appDelegate in the near future. Subclassing is the preferred method, especially because NSObject is a root class. But, that would require class posing, something deprecated completely in OSX 10.5+ and never even a viable option on iOS devices.

CodaFi
  • 43,043
  • 8
  • 107
  • 153