Will I ever need the UIApplication* application from the ApplicationDelegate functions? - ios

When would the application parameter in any of the app delegates not be equal to the shared instance?
-(void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification
{
UIApplication* sharedapp = [UIApplication sharedApplication];
if(application == sharedapp){
//things are as I expect
}else{
//some other situation I can't think of
}
}

No, there wouldn't be any situation like that.
From Documentation:
Every app has exactly one instance of UIApplication. When an app is launched, the system calls the UIApplicationMain function; among its other tasks, this function creates a singleton UIApplication object. Thereafter you access the object by calling the sharedApplication class method.

The call to [UIApplication sharedApplication] will always return a pointer to your app's shared application object. That's what the method is for.
What is the variable sharedApp you are comparing against? Presumably that's an instance variable that you defined and set to contain a pointer to your application object with an identical call to [UIApplication sharedApplication]?

Related

How to swizzle UIApplication in iOS?

I need to Swizzle UIApplication class methods especially "application:handleOpenURL:". I have added a category class of UIApplication. I have exchanged my own method with the original method but, it never triggered. The Swizzle class called very first time of app launch but, the swizzle method never triggered. I have attached the code for your reference.
- (BOOL) xxx_application: (UIApplication *) application handleOpenURL: (NSURL *) url {
NSLog(#"\n\n Swizzle handle open url..");
[self xxx_application:application handleOpenURL:url];
NSLog(#"URL: %#", url);
return YES; }
Can anyone please save my day? I tried of using some private library like "RSSwizzle" but, no help.
You don't need to swizzle this method, and it doesn't exist on UIApplication anyway. It is a method that is part of UIApplication's delegate protocol, meaning that (typically) your "app delegate" class should simply implement the method to have it called.

Call a method from AppDelegate - Objective-C

I was trying to call an existing method of my ViewController.m from AppDelegate.m inside the applicationDidEnterBackground method, so I found this link: Calling UIViewController method from app delegate, which 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 AppDelegate's implementation:
- (void)applicationDidEnterBackground:(UIApplication *)application
{
[self.myViewController method];
}
So I put this code in my project and it worked fine, but I didn't understand how the code works, line by line. What does the sharedApplication do? Why must I set a delegate instead of just creating an instance of ViewController, like:
ViewController * instance = [[ViewController alloc] init];
[instance method];
Background information (class definition vs class instance)
The important concept here is the difference between a class definition and a class instance.
The class definition is the source code for the class. For example ViewController.m contains the definition for the myViewController class, and AppDelegate.m contains the definition for the AppDelegate class. The other class mentioned in your question is UIApplication. That is a system-defined class, i.e. you don't have the source code for that class.
A class instance is a chunk of memory on the heap, and a pointer to that memory. A class instance is typically created with a line of code like this
myClass *foo = [[myClass alloc] init];
Note that alloc reserves space on the heap for the class, and then init sets the initial values for the variables/properties of the class. A pointer to the instance is then stored in foo.
When your application starts, the following sequence of events occurs (roughly speaking):
the system creates an instance of the UIApplication class
the pointer to the UIApplication instance is stored somewhere in a
system variable
the system creates an instance of the AppDelegate class
the pointer to the AppDelegate is stored in a variable called
delegate in the UIApplication instance
the system creates an instance of the MyViewController class
the pointer to the MyViewController class is stored somewhere
The storage of the pointer to MyViewController is where things get messy. The AppDelegate class has a UIWindow property called window. (You can see that in AppDelegate.h.) If the app only has one view controller, then the pointer to that view controller is stored in the window.rootViewController property. But if the app has multiple view controllers (under a UINavigationController or a UITabBarController) then things get complicated.
The spaghetti code solution
So the issue that you face is this: when the system calls the applicationDidEnterBackground method, how do you get the pointer to the view controller? Well, technically, the app delegate has a pointer to the view controller somewhere under the window property, but there's no easy way to get that pointer (assuming the app has more than one view controller).
The other thread suggested a spaghetti code approach to the problem. (Note that the spaghetti code approach was suggested only because the OP in that other thread didn't want to do things correctly with notifications.) Here's how the spaghetti code works
AppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
appDelegate.myViewController = self;
This code retrieves the pointer to the UIApplication instance that the system created, and then queries the delegate property to get a pointer to the AppDelegate instance. The pointer to self, which is a pointer to the MyViewController instance, is then stored in a property in the AppDelegate.
The pointer to the MyViewController instance can then be used when the system calls applicationDidEnterBackground.
The correct solution
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 aren't storing redundant pointers to your view controllers, and you don't have to figure out where the system has stored the pointer to your view controller. By calling addObserver for the UIApplicationDidEnterBackgroundNotification you're telling the system to call the view controller's didEnterBackground method directly.
You have two question here.
1) What does the sharedApplication do?
The [UIApplication sharedApplication] gives you UIApplication instance belongs to your application. This is centralised point of control for you App. For more information you can read UIApplication class reference on iOS developer site.
2) Why must I set a delegate instead of just creating an instance of ViewController?
Creating controller in AppDelegate again using alloc/init will create new instance and this new instance does not point to the controller you are referring to. So you will not get result you are looking for.
However in this particular use case of applicationDidEnterBackground, you don't need to have reference of you controller in AppDelegate. You ViewController can register for UIApplicationDidEnterBackgroundNotification notification in viewDidLoad function and unregister in 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];
}
The view controller is already instantiated as part of the NIB/storyboard process, so if your app delegate does its own alloc/init, you are simply creating another instance (which bears no relation to the one created the NIB/storyboard).
The purpose of the construct you outline is merely to give the app delegate a reference to the view controller that the NIB/storyboard instantiated for you.

What's the difference between [UIApplication sharedApplication] and application argument of didFinishLaunchingWithOptions?

I'm now learning about background fetch functionality in iOS 7 and Xcode 5, and I've read a few tutorials explaining how to set setMinimumBackgroundFetchInterval within application: didFinishLaunchingWithOptions: method.
One type of sample code I've read is the following one:
-(BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
[[UIApplication sharedApplication] setMinimumBackgroundFetchInterval: UIApplicationBackgroundFetchMinimum];
return YES;
}
And the other is the following, which utilizes the application argument to set its background initialization:
-(BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
[application setMinimumBackgroundFetchInterval: UIApplicationBackgroundFetchMinimum];
return YES;
However, I don't get what makes one different from the other in the two codes above. The shareApplication class method returns UIApplication *, which is exactly the same as the type of the application argument.
And if there are NOT any differences between the two, what's the point of using the former? As far as I read, there are more samples taking the first approach, but I always feel the simpler is better (again, if there is NO difference - I think some differences exists, as mentioned above).
There are no diferences, using the method parameter is useful when you don't know which class sent that message (for example, imagine that you have several UITableView, all of them with the same delegate, you want to know which one called the delegate).
In this case, there's only one UIAplication per App, and that's the one that is in your [UIApplication sharedApplication] and the one that calls the delegate.
Summarising, is just the same object and there's no diference, just style.
Extending the example, imagine that you have a variable like this:
#property (nonatomic, strong) UITableView *myTable;
Yo do:
self.myTable.delegate = self;
When the delegate is called, theres are equivalents:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
//self.myTable = tableView;
}
In this case, there is no difference.
It's probably a matter of style/preference as to which option you use.
I use [UIApplication sharedApplication].
There is no difference UIApplication is a singleton class and [UIApplication sharedApplication] is a way to access that shared variable of singleton class If you are calling the method from UIApplication class itself then using application is enough to access the method.

Setting AppDelegate Shared instance to nil does not create warning or crash

In my app, i have done something like this,
AppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
//some code
appDelegate = nil;
But, App runs fine and does not give warning or crash.
Can anybody explain this?
Thanks.
First you made appDelegate point to [[UIApplication sharedApplication] delegate]. Then you made it point to nowhere. But [[UIApplication sharedApplication] delegate] remains the same. You did nothing with it. You didn't even touch it.
What you probably are thinking of is:
[[UIApplication sharedApplication] setDelegate:nil];
But it also shouldn't produce warnings or crashes. It should only result in not calling app delegate methods since messages sent to nil do nothing.
[[UIApplication sharedApplication] delegate] will give you a pointer to your app delegate,the one that was automatically created when you made the project. So setting appDelegate = nil, just sets the pointer to the app delegate to nil. Does not do anything to app delegate, the one that is automatically created..
AppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
Using this line it return you a shared instance of appDelegate.
[UIApplication sharedApplication] --- gives access to the singleton
delegate method returns a pointer to the app delegate.
and when you assign nil to appDelegate after finishing all works. Why will it crash?
Pobably if you will try to call a method after assigning it nil value. That will not work.
You are setting your appDelegate pointer to nil not the delegate of the app. After you write this code, [[UIApplication sharedApplication] delegate] would still not be nil.

Calling methods from another class

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions: (NSDictionary *)launchOptions
{
facebook = [[Facebook alloc] initWithAppId:#"xxx" andDelegate:self];
}
I declared Facebook in my AppViewDelegate. I want use this Facebook class from my UIViewController or another class. I searched sharedApplication title but i didn't that.
Thanks for your answer.
It is possible to get it by doing:
[(AppViewDelegate *)[[UIApplication sharedApplication] delegate] facebook];
I put the cast to AppViewDelegate assuming that is the name of your AppDelegate. However, the problem with this is that you normally don't want to reference your AppDelegate from another class to use it as a class that holds a global variable.
What I would do in this situation is to use a Singleton pattern for Facebook class. Check this link Singleton Pattern

Resources