Don’t Abuse the App Delegate

Many of my tutorials (and real apps) have code in AppDelegate.m that looks like this:

- (BOOL)application:(UIApplication *)application
    didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    DataModel *dataModel = [[DataModel alloc] init];
    self.rootViewController.dataModel = dataModel;
    . . .
}

The app delegate creates the data model object and passes it to the root view controller.

The class may be called something different than DataModel, but that’s essentially what it is, the data model for the app. In a Core Data app, this could be an instance of NSManagedObjectContext.

At some point, the root view controller opens another screen, and it passes along the DataModel object to this new view controller:

- (void)tableView:(UITableView *)tableView
    didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    SecondViewController *controller = [[SecondViewController alloc]
        initWithNibNamed:@"SecondViewController" bundle:nil];
    . . .
    controller.dataModel = self.dataModel;
    . . .
    [self presentViewController:controller animated:YES completion:nil];
}

Invariably, someone asks: “Why not simply ask the AppDelegate for that data model object?”

They propose code such as this:

// Somewhere in SecondViewController.m:
- (void)someMethodThatNeedsTheDataModel
{
    DataModel *dataModel = ((AppDelegate *)[UIApplication
        sharedApplication].delegate).dataModel;
    . . .
}

That looks a bit ugly, but you can always “work around” that with a macro:

// In your Prefix.pch file:
#define MY_APP_DELEGATE ((AppDelegate *)[UIApplication sharedApplication].delegate)
 
// In SecondViewController.m:
- (void)someMethodThatNeedsTheDataModel
{
    DataModel *dataModel = MY_APP_DELEGATE.dataModel;
    . . .
}

The DataModel object is now a property on the AppDelegate class, and you can “just” ask for it whenever you want. Easy right?

I don’t know who came up with this idea, but it seems widespread, especially among beginners. It’s also a quick fix with harmful consequences.

So what is the difference?

My preferred approach requires you to pass the DataModel object (or objects) from each view controller to the next, or at least to those that need it. That seems like more work, but it has an important advantage: your view controllers only depend on the objects that they directly need.

It is a good object-oriented design principle to limit the dependencies between your objects. The looser your objects are coupled, the better.

This is what the principle looks like in a picture:

The view controllers pass around the DataModel object

However, when all your view controllers depend on the app delegate, the diagram looks like this:

All the view controllers are now connected to the AppDelegate

The problem is this: As your app grows, it will have a lot of classes that have many interconnections between them. The greater the number of connections, the harder it is to understand what is going on in your code, and the harder it is to make changes. If you’re not careful, your code will become a big mess — and we all know where bugs love to hide.

By using the app delegate this way, you’re adding even more complexity to the web of connections. Each view controller now has to reach out to AppDelegate to get the data it needs to do its job.

You’re also giving AppDelegate too much to do. Before you know it, it has become this humongous class that is responsible for just about anything in your program.

Passing around objects all the time seems like a chore, but it’s the cleaner design. Consider each view controller in your app an island that can function independently of all the other view controllers, given the data model objects it needs for its calculations.

What should the app delegate do?

The app delegate performs an important function in your app but is not intended to be some magic singleton that holds all your data.

It is the place where you receive notifications that concern the application as a whole: the app is launched, the app is about to go into the background, the app has returned from the background, and so on. You should restrict the role of the app delegate to just handling those notifications.

The app delegate is where your app initializes itself — it creates the window and loads the initial view controller, it creates the data model objects or Core Data store — and then it passes control to that initial view controller. Beyond that, the app delegate should just handle the application-wide notifications and do nothing else.

So if you feel tempted to write,

[UIApplication sharedApplication].delegate

anywhere in your code, then it’s time to rethink your class design.

Comments

  1. Scott says:

    What are your thoughts about using a Singleton for data access? I’ve previously used both these methods you’ve described in past apps, but found either had faults, some of which you’ve described. Now I use a singleton to control all access to stored data.

  2. Vadym says:

    Hey Matthijs, thanks a lot for the post. I liked it because I like rethinking basic concepts over and over again :D
    I definitely agree that app delegate is not designed for all that stuff developers usually tempted to do with it.
    Sorry for shifting a bit away from the app delegate, but still, my response has a lot to do with the topic.
    My usual approach in solving this problem is a separate singleton class. Yes, I can see that class dependency diagram will look messy then, but it doesn’t change a matter of things anyway. In passing-a-parameter approach all the view controllers are still depend on DataModel, the only difference is how they communicate with it. I mean in any way a lot of code parts in a project need some central point to get data off. Or they all have to implement data fetching logic inside themselves which is more messy approach.
    What are the bad practical consequences of the singleton approach? Is it going to work slower? Definitely not. Harder to maintain? I don’t think so. If you ever change DataModel class’ behavior it doesn’t matter which way it has been implemented, it’ll influence on its consumers anyway.
    I can say even more, having DataModel class as a singleton makes its consumers more independent because they can make use of it whenever they need. And they can easily refuse using it. In other way you have to pass it in the calling code, you have to modify view controller’s initializer to support such parameter and you have to maintain a property inside every view controller. Too much efforts for such a simple task.
    So, it’d be really interesting for me to hear what you think about that, maybe I missed some points.

  3. Ross Kimes says:

    I currently have my data model set up just like you recommend. I initialize it in the data model and just pass it everywhere I need it. I was thinking about simplifying my approach a little by making it a singleton. What do you think of that approach?

  4. Ross Kimes says:

    Sorry….initialize it in the app delegate*

  5. Mohammed says:

    Thanks for this valuable piece of information and codes :)

  6. Matthijs says:

    @Scott, @Vadym, @Ross: Singletons are probably a good topic for another post (he he) but I am no fan of them. If you pass to an object all the data that it needs, then the dependencies between these objects are clear. However, singletons tend to hide these dependencies because they are basically global data that can be accessed from anywhere. I like my code to be obvious when you look at it, and that means it cannot have hidden side effects, and so all dependencies must be clear.

  7. Pingback: Stop abusing App Delegate « DaVinC Coder

  8. Matt says:

    I know this is standard wisdom, but I don’t buy it. Passing the object around is more complex than having a single source.

    All apps have an app delegate and it stays around forever. The app delegate is already a Singleton in every application, and can be depended on as such. All Core Data apps have the app delegate be the creator and owner of at least one NSManagedObjectContext.

    The standard guidelines of OO complexity avoidance shouldn’t apply to a single core Singleton that will always exist in every application. Passing a context around leaves more room for error and is more complex.

    There are plenty of abuses of the app delegate (the common temptation to treat it as a generic Singleton-provider-of-everything). The managed object context is of low concern, and in this case reduces complexity.

  9. Andrea Mariottini says:

    In general singletons are a bad idea:
    - you can’t unit test a class depending on a singleton, you need that singleton
    - you can’t replace a singleton with another without changing all your code
    - you can’t change the behavior of the application without changing the code of all the classes using a singleton

    Of course in rare situations you may need a singleton but as I know this can be useful when developing frameworks and not applications (UIApplication is a singleton).

    Imagine this: you write the model as a singleton using CoreData and you spread the use of the singleton in a lot of classes. Then you want to make your app persist data not on the local database but on the cloud maybe using some REST service.
    You have to write another model and change all the classes to use the new one.
    Injecting the model as Matthijs says you have to change only one line of code.

    In general singletons breaks SOLID principles and aren’t a good OO pattern.

  10. mcapelle says:

    Just à question about the way you pass your model usine arguments.
    What about if your firstview doesn’t need your model and your secondview needs it ?

    It means that you needs to give your model to the firstview just to give it to the secondview.
    Isn’t it a problem ?

  11. Ranjit K says:

    Thanks Matthijs , for this informative post, it cleared some of my doubts..

  12. Matthijs says:

    If “firstview” depends on “secondview”, then it also depends on the data that “secondview” needs to operate, so I don’t see this as a problem.

  13. Andrea Mariottini says:

    You could even inject the model into the “secondview” and then inject the “secondview” into the “firstview”.
    This way “firstview” doesn’t depend on the model, it depends of course on “secondview”.
    This is a typical approach outside iOS, maybe is not the best on iOS where memory management is critical.
    But if your app has only some views I think this is not a problem.

  14. Matt says:

    “Injecting the model as Matthijs says you have to change only one line of code.”

    @Andrea Or you change the getter in your app delegate to return a different object. Still only one point of change, and no greater complexity.

    When the object you’re passing around is the same context object that the app delegate is already retaining for the lifetime of the app there’s no pragmatic gain to be had from passing it around instead of requesting it at use time from the original owner.

    Personally I have my app delegate’s context getter return either its retained main thread context or a fresh context depending on whether it was called from the main thread or not. Any method that uses a context requests said context within itself and thus gains some implicit thread safety without added code complexity.

    Though there’s still the concern of manipulating managed objects that are associated with a different context, which is a matter of careful app design that anyone using threaded Core Data needs to be conscious of, and other OO principles can be applied to reduce the pitfalls there.

  15. Matt says:

    Further, in response to @Andrea, whether you pass the context around controller to controller or request it from the app delegate, so long as you have depended on the Core Data API you cannot simply swap the context out with a REST based object and continue without code changes.

    In order to do that you would need to have wrapped the Core Data APIs in a Bridge or Facade pattern from the beginning, or alternatively have your REST API exactly mimic the Core Data APIs.

    Again, requesting the context from the app delegate or handing it around does not change those required concerns.

  16. Andrea Mariottini says:

    @Matt “In order to do that you would need to have wrapped the Core Data APIs in a Bridge or Facade pattern from the beginning, or alternatively have your REST API exactly mimic the Core Data APIs.”

    Yes. This is why I think is better to decouple application classes from AppDelegate and pass the model around behind a protocol (for example)!

    What I said is pass the model not the context, the CoreData context is a framework specific object, the model should be an application specific object.

  17. Matt says:

    @Andrea Sounds like you’re going for perfect OO :)

    I think of classes as having two types: reusable and not reusable.

    Reusable: Classes designed to be usable in multiple apps with no modification. These should conform to perfect world OO and should pass the test of “Can be submitted to Github and used by other people with zero modification”.

    Not reusable: Classes designed to be only usable in the current app, and are allowed to make assumptions about the current app’s architecture. These do not need to conform to textbook OO principles.

    I see view controllers (and almost only view controllers) as being of “not reusable” type. They are app specific logic and can (and often should) assume things like the existence of an app delegate, the services that app delegate provides, the use of Core Data, etc.

    Reusable classes, however, can interact with the data or the UI but are only allowed to know as much as they need to know to do their task. These classes shouldn’t be given a raw context or raw managed objects.

    Any logic happening in the view controller that could conceivably fall into the “reusable” type should be extracted from the view controller and made a separate class. If it is left in the view controller then the app is using OO only by syntax and not by principle, and might as well be written as flat functions instead of objects.

  18. Andrea Mariottini says:

    @Matt

    Yes, view controllers are by definition not reusable because they are specific for a given UI.
    Even models are often not reusable.

    Anyway IMHO try to follow good OO principles makes application development and maintenance more fast and safe.
    This doesn’t mean OO principles are a silver bullet and are always appropriate…

  19. Stuart Ervine says:

    @Andrea,

    I was going to leave a comment, but read the ones left by you and Matt, and realised you’ve said exactly what I would have. From your comments, I’m guessing you have at least some experience of a test driven approach.

    It is good to see other people pushing away the singleton approach, and opting to inject adapters/bridges to the core API services such as Core Data and Location Management.

    @Matt

    The complexity diagram in the original blog post shows exactly the problem I see in a lot of iOS code knocking around in examples on the internet. People incorrectly assume singletons will solve this dependency problem, IMO they add to problem by hiding the true dependencies.

    Looking forward to more.

  20. Panupan S says:

    Great post. When two classes reference each other, bad things are bound to happen… avoid circular dependencies folks!

  21. Michael says:

    This seems like an older post, but I do have to disagree slightly with this. Sure it seems straight forward enough when dealing with some like Core Data that will most likely be required for the majority of the views. But what about when it comes to integrating Twitter with the TWRequest class where you manage the accounts and can only have a singleton instance of ACAccountStore. You may not need this on every page. In Apples own WWDC they suggest creating this in your appDelegate.

    For example what if you require the account information to tweet something 3 levels deep? Are you going to pass useless twitter account information from controller to controller just to have it maybe used when it is required on a view 3 levels deep because that follows good OO practice? I would argue that is bad modelling.

    I get what the post is trying to achieve, and I agree. But I also must point out there are different models for different reasons. There is never a one size fits all solution.

  22. Wakjob says:

    Problem with this approach is that it will require you to access other view controllers, which sub-view controllers shouldn’t need to know about. Far better to just access the shared delegate from anywhere than to have to have cross references to other view controllers inside other view controllers. The whole point of controllers it to encapsulate functionality. If they all need to know about each other, what’s the point of even having separate controllers. The data model should live in the app delegate. That way it is truly and totally independent of any view controllers.

  23. Matthijs says:

    In my view, it is perfectly acceptable that if view controller A presents view controller B, that A also gives B any data objects that it needs, no matter how deep the hierarchy of view controllers goes. B is independent of A, but there is no reason why A should be independent of B. After all, A calls B for a reason.

  24. Vassilis Aggelakos says:

    Hi Matt,
    thank you very much for all your great work on IOS tutorials, I have a “simple” question regarding the subject: my login screen retrieves a token from a webservice (a simple string) which I have to pass it along to the next screen. My problem is (I use storyboards) that the next controller that is called is a UINavigationController which then loads a UITableViewController internally . Between UINavigationController and UITableViewController there is only a relationship and not an actual segue. Can you please advice me how to send my string “over” the navigationController?

    Thank you *very* much for your time.
    Vassilis

  25. Vassilis Aggelakos says:

    Hi Matt again,
    Problem solved I had totally forgotten about the topViewController property of the navigationController.

    Thanks anyway!

  26. Jamie McDaniel says:

    Thanks for this discussion!

    Coming to Objective-C from Adobe Flex, I really miss having a dependency injection framework.

    What you describe, Matthijs, is “dependency injection”. However it is not the type of dependency injection I am used to because of the problem that mcapelle expressed.

    If an object 3 levels deep has a dependency, that really should not be passed down from its grandparent and parent — especially if those objects did not otherwise have that dependency themselves. What if you refactor and move the grandchild object somewhere else? You then have to establish that dependency on all its new parents and remove it on the old ones.

    In Flex, this problem was solved by having a dependency injection framework such as Swiz or Robotlegs that would create all the singletons (little s). Other objects would declare what objects they depended on and these would be injected by the framework. Thus an object many levels down would gets its dependencies fulfilled without having to pass that data down many layers.

    I remember reading about Singleton (capital “S”) versus singleton (lowercase “s”). Basically, if a class has a getInstance or sharedInstance method, it is a capital “S” Singleton. Whereas if it is just the single instance that an application uses and is injected wherever it is needed, it is a lower case “s” singleton.

    Here is where I read about that:
    http://misko.hevery.com/2008/08/25/root-cause-of-singletons/

  27. Kenrik says:

    Interesting topic, there are pros and cons both ways. I disagree that a controller should “always” be passing the model up the chain I’ve had plenty of instances where the app structure had to be refactored and these type of connecting interfaces would have made it much more difficult (and I think an equal number where it made sense to do it that way). I dislike when things like this are presented in black and white and if you’re not doing it X way you’re doing it “wrong” IMO almost everything is a shade of grey.

Leave a Reply

Your email address is required but will not be visible to others.

 *
 *