2

I just ran myself round in circles, all coming down to having instantiated an app delegate object in a secondary NIB that wasn't the NSMainNibFile. Amazing how having two app delegates kicking around means you have separate managedObjectContexts.

Here's a thought-- could I make my application delegate class a singleton? And safely instantiate it in more XIBs? What would that break?

Also, there are some mentions on stackoverflow that [[UIApplication sharedApplication] delegate] is a "singleton" but it doesn't appear that UIApplicationDelegate protocol guarantees that, nor is the superclass UIResponder a singleton, either. So could I shoot myself in the foot in this regard on iOS as well?

[edit] Looks like you could nil out the delegateClassName in UIApplicationMain for iOS and have the main NIB load the delegate object, so you could create the App Delegate object pattern seen on OSX, if using a main NIB.

[edit2] Screenshot of what MainMenu.xib looks like for a new non-document application. The project gets created with this object, app delegate class gets created with a window property. The issue is getting that nice handy object in other NIBs, and that object being the same as [NSApp delegate] enter image description here

stevesliva
  • 5,351
  • 1
  • 16
  • 39
  • 2
    There *is only one* application delegate, the one that was set when the app started. You can create a second *object* of the app delegate class, but it's not an app delegate, regardless of the name. (And note that you can do the same thing with a singleton class -- create multiple instances outside of the "factory".) – Hot Licks Apr 04 '14 at 20:03
  • (You shouldn't be creating app delegates in an XIB. I'm not even sure how you can do that.) – Hot Licks Apr 04 '14 at 20:05
  • 1
    @Hot Licks -- just create an object with the custom class set to your app delegate class. And incidentally, the application's delegate get set when the main nib file is loaded somewhere in NSApplicationMain, which is why the main NIB gets away with it. To be clear-- doing this was BAD, because the delegate class doesn't guarantee a single instance of that class. – stevesliva Apr 04 '14 at 20:08
  • OK, I was speaking of iOS, where the app delegate is loaded in `main`, by convention. – Hot Licks Apr 04 '14 at 20:27

3 Answers3

0

Okay, after the question having been voted up, and then voted down to zero because of who-knows-why, I've continued to investigate my own answer. I think it's useful to make your app delegate classes true singletons so you can't cause headaches with NIBs. I can't see why it would be harmful. And I think if your app has a single user interface, it's not unreasonable to have the app delegate own the core data stack for all NIBs. However, the recommended design pattern would be to then have each window or view controller be passed the ManagedObjectContext pointer, and to access the MOC through the File's Owner placeholder rather than using an App Delegate object.

Yet on the other hand, things are different with the "Shared User Defaults Controller" singleton, which gets a special object in every NIB. We don't have to pass every controller a pointer to it so that every view can access it. It's just omnipresent. The app delegate is different. There's no "Shared App Delegate" object in every NIB. Yes, there are reasons to never talk to the app delegate in NIBs, but that's not an answer to the question.

So, an answer.

Singleton design patterns: Covered long ago by Apple in this deprecated reference document-- Creating a Singleton Instance.

Turns out what I want my application delegate class to implement is the "strict" implementation, rather than having a factory method which could create other objects of the app delegate class. The one different feature here is having [NSApp delegate] be the master pointer rather than an app delegate class function.

The strict implementation has to override allocWithZone for my application delegate class (as alloc calls allocWithZone).

+ (MYAppDelegate*)allocWithZone:(NSZone *)zone
{
    if ([NSApp delegate] == nil) return [super allocWithZone:zone];
    return [NSApp delegate];
}

- (MYAppDelegate*)copyWithZone:(NSZone *)zone
{
    return self;
}

Init just returning [super init] is fine, so it needs no override.

Seems to work. I'll update this if not.

[update] I have also been investigating NIB loading using NSBundle's loadNibNamed:owner:topLevelObjects: -- but it appears that I'd get an array back with a new app delegate object, even from that method. The method allows getting pointers to the top-level objects in the NIB without having otherwise created outlets for them. Still seems the best method to get an app delegate object in a XIB other than MainMenu is to use something like the code above.

[another update] Why it could be harmful: According to the the section "Top-level Objects in OS X May Need Special Handling" in this document, there's good reason for me to believe that, even with ARC, this answer of mine increases the retain count on [NSApp delegate], but heck if I feel okay doing a bridge and a release on the app delegate in dealloc for the window/view controllers that have a top-level object for the app delegate. Plus that means code outside the app delegate class.

stevesliva
  • 5,351
  • 1
  • 16
  • 39
  • 1
    It still seems pretty weird to have a NIB create the app delegate, rather than the `main` function, or whatever counts for that. – Hot Licks Apr 04 '14 at 21:46
  • `NSApplicationMain` and `UIApplicationMain` take care of hooking in the singleton application delegate. In OSX, the NSMainNibFile, usually MainMenu.xib, has an app delegate object which is hooked up as a part of NSApplicationMain. UIApplicationMain has this as an option. What this code does, is allow the app delegate object in other NIBs, which will call init. Might be retain issues, but because it's the app delegate... – stevesliva Apr 04 '14 at 21:49
  • Yes. An alternative answer might be that you should subclass the window or view controller and make sure it has a managedObjectContext property set to the managedObjectContext that the app delegate created. And then create bindings to File's Owner's managedObjectContext. That is what your link suggests. The alternatives like my answer above, or this: http://gentlebytes.com/blog/2009/09/02/coredata-bindings-multiple-nibs/ are pretty ugly. – stevesliva Apr 07 '14 at 18:07
  • Or and IB-centered alternative: http://stackoverflow.com/questions/20180939/unable-to-use-managed-object-context-proxy-from-interface-builder-library ... drag the MOC object into your NIB and connect it to the delegate's PSC in awakeFromNib, though you then have a separate MOC, which would recreate the issues that got me here. – stevesliva Apr 07 '14 at 18:14
0

Just do this in your existing App Delegate (There will only be one!)

// In the header file    
+ (AppDelegate*) sharedInstance;


// In the body
+ (AppDelegate*) sharedInstance {

    return (AppDelegate*) [[UIApplication sharedApplication] delegate];

}

Then anywhere you want to refer to your App Delegate, you can simply use [AppDelegate sharedInstance] followed by the property or instance method you want to call.

Sammio2
  • 7,422
  • 7
  • 34
  • 49
  • Wouldn't work in a XIB-- all you can specify is the class type. Not a class method. If you could call any method, I'd call `[NSApp delegate]` -- but the XIB's just going to alloc-init the custom class, as far as I know. – stevesliva Apr 04 '14 at 22:20
  • Yep, totally misunderstood the question... the edit's help clarify what you're after. Sorry! – Sammio2 Apr 05 '14 at 11:42
0

You shouldn't be using the app delegate for stuff to do with core data anyway. So making it an enforced singleton is pointless.

Ideally nothing should need to reference back to it at all.

Fogmeister
  • 76,236
  • 42
  • 207
  • 306
  • I tend to agree, but in a non-document application, the templates suggest that the app delegate owns managedObjectContext stack, and this is also the case where xcode creates this app delegate object. Say you have an app with a billion windows like GIMP but that isn't doc-based-- where's your shared MOC pointer? – stevesliva Apr 04 '14 at 23:06
  • For the person who down voted... http://www.hollance.com/2012/02/dont-abuse-the-app-delegate/ – Fogmeister Apr 07 '14 at 07:28
  • Stumbled upon this today, "In OS X: In an single-coordinator applications, you can get the application’s context directly from the application delegate." -- [Apple's "Accessing the Core Data Stack"](https://developer.apple.com/library/ios/documentation/DataManagement/Conceptual/CoreDataSnippets/Articles/stack.html) – stevesliva Apr 27 '14 at 02:44