Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Does referencing an iOS app delegate in a block create a copy of the delegate object?

Consider the following example:

- (void)exampleFunction
{
  AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
  SomeClass *classObject = [[SomeClass alloc] init];
  [classObject someFunctionThatDoesBackgroundWorkAndCallsACompletionBlock:^(NSDictionary *results) {
    SomeNeatObject *object = appDelegate.someNeatObject;
    [object doSomeNeatStuff:results];
  }];
}

Making an assumption that the completion block is executed on the main/UI thread to avoid additional insanity, here's what I'm unsure of:

  1. Does the appDelegate variable get copied onto the stack, as per normal block rules when referencing variables inside the block?
  2. If yes to #1, is this a good / safe practice? I could see this possibly causing problems if you did this in a block that was subsequently dispatched to a GCD queue, as .someNeatObject could have changed state / gone to nil?

I realize that the appDelegate should not be overused, but it is useful for it to hold information about the current state of the application, such as Core Data-related objects if you use Apple's templates for initializing a Core Data stack (at least on iOS projects). That particular case (Core Data) has me concerned as much of that stack is not thread-safe nor is it a good idea to be copying it.

Thanks in advance.

like image 565
Matt S. Avatar asked Apr 03 '14 01:04

Matt S.


1 Answers

Your example will not compile because delegate is not defined. I assume you mean "SomeNeatObject *object = appDelegate.someNeatObject;"

In this example, appDelegate is a variable, whose value will be captured by the block. It's no different than any other variable.

It's not unsafe, because [[UIApplication sharedApplication] delegate] always returns the same thing, unless you change the delegate, which you probably don't.

The fundamental concepts here are: appDelegate is a variable which points (or refers) to an object (or instance) of type AppDelegate. In an iOS app there is one such instance, which is returned by [[UIApplication sharedApplication] delegate]. If you create a reference to appDelegate inside a block, you are making a copy of the variable, not the object. So in your code's block:

SomeNeatObject *object = appDelegate.someNeatObject;

This is semantically the same as putting the following code in the block (casts omitted):

SomeNeatObject *object = [[UIApplication sharedApplication] delegate].someNeatObject;

The SomeNeatObjects being referred to are the same thing.

Slightly more advanced concept: any object has an address in memory (an integer, usually seen in hexadecimal). If two variables have the same hexadecimal value, they point to the same object. If they have different values, they point to different objects. In your example, appDelegate (outside block) and appDelegate (inside block) have the same value, therefore point to the same object.

If you were to do this:

AppDelegate * otherDelegate = [appDelegate copy];

Then you would be making a copy of the object pointed to by appDelegate. But don't do this, please.

like image 115
Sofi Software LLC Avatar answered Nov 06 '22 07:11

Sofi Software LLC