Call a method from AppDelegate - Objective-C

I tried to call the existing method of my ViewController.m from AppDelegate.m inside the applicationDidEnterBackground method, so I found this link: Calling the UIViewController method from the application delegate who told me to implement this code:

In my ViewController.m

 -(void)viewDidLoad { [super viewDidLoad]; AppDelegate *appDelegate = [[UIApplication sharedApplication] delegate]; appDelegate.myViewController = self; } 

In my AppDelegate:

 @class MyViewController; @interface AppDelegate : UIResponder <UIApplicationDelegate> @property (weak, nonatomic) MyViewController *myViewController; @end 

And in the implementation of AppDelegate:

 - (void)applicationDidEnterBackground:(UIApplication *)application { [self.myViewController method]; } 

So, I put this code in my project and it worked fine, but I did not understand how the code works, line by line. What does sharedApplication do? Why should I set a delegate instead of instantiating the ViewController, for example:

 ViewController * instance = [[ViewController alloc] init]; [instance method]; 
+8
ios objective-c iphone uiviewcontroller appdelegate
source share
3 answers

Background information (class definition and class instance)

An important concept here is the difference between a class definition and an instance of a class.

The class definition is the source code for the class. For example, ViewController.m contains a definition for the myViewController class, and AppDelegate.m contains a definition for the AppDelegate class. Another class mentioned in your question is UIApplication . This is a system class, i.e. You do not have source code for this class.

A class instance is a piece of memory on the heap and a pointer to that memory. A class instance is usually created using a line of code like this

 myClass *foo = [[myClass alloc] init]; 

Notice that alloc reserves heap space for the class, and then init sets the initial values ​​for the class variables / properties. The pointer to the instance is then stored in foo .

When your application starts, the following sequence of events occurs (roughly):

  • the system creates an instance of the UIApplication class
  • a pointer to a UIApplication instance is stored somewhere in the system variable
  • the system creates an instance of the class AppDelegate
  • a pointer to AppDelegate is stored in a variable called delegate in the UIApplication instance
  • the system creates an instance of the MyViewController class
  • a pointer to the MyViewController class is stored somewhere

Storing a pointer to a MyViewController is where things get messy. The AppDelegate class has a UIWindow property called window . (You can see this in AppDelegate.h.) If the application has only one view controller, a pointer to this view controller is stored in the window.rootViewController property. But if the application has several view controllers (under the control of UINavigationController or UITabBarController), then everything becomes more complicated.

Spaghetti Code Solution

So, the problem you are facing is this: when the system calls the applicationDidEnterBackground method, how do you get a pointer to the view controller? Well, technically, the application delegate has a pointer to a view controller somewhere under the window property, but there is no easy way to get that pointer (assuming the application has more than one view controller).

In another thread, an approach to the problem of spaghetti was proposed. (Note that the spaghetti codes approach was proposed only because the OP in this other thread did not want to do something correctly with notifications.) Here, how the spaghetti code works

 AppDelegate *appDelegate = [[UIApplication sharedApplication] delegate]; appDelegate.myViewController = self; 

This code retrieves a pointer to a UIApplication instance created by the system, and then queries the delegate property to get a pointer to an AppDelegate instance. A pointer to self , which is a pointer to an instance of MyViewController, is then stored in the AppDelegate property.

A pointer to an instance of MyViewController can then be used when the system calls applicationDidEnterBackground .

The right decision

The correct solution is to use notifications (as in kkumpavat's answer)

 - (void)viewDidLoad { [super viewDidLoad]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didEnterBackground) name:UIApplicationDidEnterBackgroundNotification object:nil]; } - (void)didEnterBackground { NSLog( @"Entering background now" ); } -(void)dealloc { [[NSNotificationCenter defaultCenter] removeObserver:self]; } 

With notifications, you do not save redundant pointers to view controllers, and you do not need to determine where the system has saved a pointer to your view controller. addObserver calling addObserver for UIApplicationDidEnterBackgroundNotification , you tell the system to directly contact a controller of the kind didEnterBackground .

+16
source share

You have two questions.

1) What does sharedApplication do?
[UIApplication sharedApplication] gives an instance of UIApplication that belongs to your application. This is a centralized management point for your application. For more information, you can read the link to the UIApplication class on the iOS developer site.

2) Why should I set a delegate instead of instantiating the ViewController?
Creating a controller in AppDelegate again using alloc / init will create a new instance, and this new instance will not point to the controller you are referring to. This way you will not get the result you are looking for.
However, in this particular case of using applicationDidEnterBackground you do not need to have a link to your controller in AppDelegate . You ViewController can register to notify UIApplicationDidEnterBackgroundNotification in the viewDidLoad function and unregister in the dealloc function.

 - (void)viewDidLoad { [super viewDidLoad]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(yourMethod) name:UIApplicationDidEnterBackgroundNotification object:nil]; //Your implementation } -(void)dealloc{ [[NSNotificationCenter defaultCenter] removeObserver:self]; } 
+6
source share

The view controller is already created as part of the NIB / storyboard process, so if your application delegate makes its own alloc / init , you simply create another instance (which has nothing to do with the NIB / storyboard).

The purpose of the constructed design is to simply give the application delegate a link to the view controller created for you by the NIB / storyboard.

+4
source share

All Articles