While fixing third-party code I've discovered a really brilliant idea) Guy was using 2 appDelegate objects in project xibs. I assume he thought that this would be some kind of singletone or such. But after some rethinking of that piece of code, I found that there is no technical restrictions on it.
Here is my example: simple project with navController and 2 views. Each with it's viewController. When app launched, first view is on screen. When user taps button, second view is pushed to navController. For now there is appDelegate object in MainWindow.xib. Now, if you'll add just the same appDelegate object to second view's xib. Now right when second view is pushed, you can see that one more instance of appDelegate is created and destroyed (if you'll override init and dealloc methods and insert log there).
Here I'm very surprised. Does it mean that only one appDelegte instance can be created? If yes, then why? appDelegate is just a NSObject subclass implementing UIApplicationDelegate protocol.
The appDelegate object created by xCode on every iphone project is the entry and exit point of an application. It does not make sence to have more than one instance of this class, if you do (besides perhaps some application settings being lost) which class does the applicaiton delegate to? Why can you only make one? Most probably this is because the class is implementing a Singleton patterns under covers so ensure only one instance of the app delegate is made, i bet that even when you try to alloc another one of these, the original app delegate is the only one kept. You can probably dig around the docs and find more info on apples site at http://developer.apple.com/iphone
UIApplicationDelegate is a protocol and doesn't have state in itself, thus there's nothing that prevents you to have several of them. Contrast this with UIApplication that has state and
provides sharedApplication singleton accessor
It should be totally possible to replace UIApplication's delegate property on the fly. I don't see much of the benefit, though.
I think what's happening here is that there is an instance of the AppDelegate class in the second Nib, but no other objects are retaining it. Therefore it gets created and immediately released. If you added a retained property to the view controller that connected to the AppDelegate, then it wouldn't get released immediately.
You can have multiple objects that implement the UIApplicationDelegate protocol, but it's not usually done because 90% of the behavior would be identical in all cases.
I think you could do something along these lines:
Note the old UIApplication.delegate.
Create your instance of UIApplicationDelegate with the old delegate as parameter.
Make sure to call the old delegate in each method you implement.
Make it return the old delegate in the - (id)forwardingTargetForSelector:(SEL)aSelector method.
Replace the [UIApplication sharedApplication].delegate with yours.
It replaces the original app delegate with your, making sure that the old delegate will still be called, especially if you did not override each and every method the UIApplicationDelegate protocol defines.
Related
I'm trying to get an instance of my AppDelegate accessible to all methods in each ViewController that I have. If I try to declare it with other class variables I get Initializer Element is not a compile-time constant. If I declare it in a method within the ViewController however I am able to use it. I am trying to save integers and floats to properties I have set up in the AppDelegate (a big no-no I know, but this is a project for an introductory class and I'm not expected to get too advanced, especially since everything we've done so far is not compliant with the MVC paradigm). The app uses a toolbar to switch between views using the app's ViewController to load the other ViewControllers as subviews. I was going to put the AppDelegate declaration and update statements in the ViewDidUnload method of each view controller, but I'm not sure that the Views are unloaded whenever they are switched (they're switched by removing the current View from the SuperView and loading the new one as a Subview at index 0). What happens to the views that are not currently being viewed then? Is there a method that detects that that I could implement the AppDelegate declaration and updates into?
I guess ideally I'd like to be able to access the AppDelegate object in any method in my ViewControllers because I have a lot of quantities being updated throughout and would like to have those quantities updated in the AppDelegates values as soon as they happen, since I'm not sure what happens with a View is cleared from SuperView
Thanks in advance everyone
You can access your app delegate via [[UIApplication sharedApplication] delegate] from anywhere in your application.
You should never instantiate another copy of the object on your own. The system does this for you at startup.
As for detecting changes, you can override the viewDidDisappear method of UIViewController. (You're correct--in general, they will not be unloaded when switched, and viewDidUnload will not be called)
I have 2 or 3 views in my iPhone application where I have various pieces of functionality that use delegates. In all cases the delegates are assigned to "self", responding specifically to that view's actions and interacting with instance variables.
However, if I do something that takes a bit of time with a delegate, and leave the view, obviously it crashes my app as the delegate methods get called on a view I've left.
Typically in my delegate methods I am doing things like interacting with IBOutlets, calling other instance methods, saving data to Core Data etc...
How can I work with delegates better? Is what I'm doing typical, or not?
Thanks for any guidance!
Depends on the use case. If, for example, you've got a UINavigationController that manages a ViewController that use something such as Location Services, when you pop the View Controller off of the stack you're going to want to set the CLLocationManager's delegate to nil. You can do this in the dealloc method.
Can you give a specific example of an issue you're facing?
I've encountered this situation once when dealing with MapKit (race conditions involving delegate callbacks and delegate deallocation). However, in general, I think it's an indication of a bad design decision when your delegate becomes invalidated as a result of race conditions, but I could be wrong.
Typically, the objects that make use of your delegate should exist within the context of the delegate itself. So, for example, the same class that contains various IBOutlets that you want to manage with delegate callbacks should also be the delegate of those IBOutlets. That way, when the class (i.e., the delegate) is deallocated, the IBOutlets are (hopefully) also deallocated, so they won't be making callbacks to anything.
bpapa's right. More generally, if you have a potentially lengthy delegate callback, either make sure that 1) the delegate is an object that won't be deallocated during the lifecycle of the delegator (e.g., UINavigationController managing UIViewControllers) or 2) the delegator's delegate object is set to nil during the delegate's deallocation.
... That last sentence was a mouthful. :)
Your delegates should be declared as
#property (nonatomic, assign) id <MyDelegateProtocol> delegate;
This ensures a weak reference so that when you dealloc the object which has delegate, it only removes the reference and NOT the corresponding object. using (strong) will cause a crash on dealloc.
When calling your delegate, you can check
if (self.delegate && [self.delegate respondsToSelector:#selector(MyDelegateProtocolCallbackMethodName:)] {
[self.delegate MyDelegateProtocolCallbackMethodName:result];]
}
Generally I use delegates for proxy classes which fetch data from a server or edit screens like changing the title of a task in a todo list or editing a model in a database.
The advantage of a delegate is a very clear use case. If you find that multiple parts of your app need to be aware of when an event happens (triggered on 1 screen but perhaps listened for in another), I suggest using NSNotificationCenter to raise notifications, instead of or perhaps in addition to sending a message to your delegate.
I'm working through an iPhone tutorial (link text and it has me put in some code (a few times throughout the various tutorials) but it doesn't explain it at all.
In this code:
todoAppDelegate *appDelegate = (todoAppDelegate *)[[UIApplication sharedApplication] delegate];
What exactly is an appDelegate? What does the "delegate" at the end of the instantiation mean? Actually, what does the whole thing mean? (UIIapplication sharedApplication)?
I am a .Net programmer if that helps someone explain it better. I hate learning through tutorials because I always need to know what EVERYTHING does and no one explains everything.
Let's back up a little bit.
The square brackets ([ ]) are Objective-C's method calling syntax. So if Cocoa had a C# syntax, the equivalent syntax would be:
TodoAppDelegate appDelegate = UIApplication.sharedApplication.delegate;
In C#, you would use a static class for a class that only has a single instance. In Cocoa, the Singleton pattern is used to accomplish this. A class method (in this case, sharedApplication) is used to retrieve the single instance of that class.
Delegates in Cocoa are not like the delegate keyword in C#, so don't be confused by that. In C#, you use the delegate keyword to reference a method. The delegate pattern in Cocoa is provided as an alternative to subclassing.
Many objects allow you to specify another object as a delegate. Delegates implement methods that those objects will call to notify them of certain events. In this case, UIApplication is the class that represents the current running application (similar to System.Windows.Forms.Application, for example). It sends messages to its delegate when things that affect the application happen (e.g. when the application launches, quits, gains or loses focus, and so on.)
Another Objective-C concept is the protocol. It is similar in principle to a .NET interface, except that methods can be marked as #optional, meaning they classes are not required to implement the methods marked that way. Delegates in the iPhone SDK are simply objects that conform to a specific protocol. In the case of UIApplication, the protocol delegates must conform to is UIApplicationDelegate.
Because it's not required to implement every method, this gives the delegate flexibility to decide which methods are worth implementing. If you wanted to, for example, perform some actions when the application finishes launching, you can implement a class that conforms to the UIApplicationDelegate protocol, set it as the UIApplication instance's delegate, and then implement applicationDidFinishLaunching:.
UIApplication will determine if its delegate implements this method when the application finishes launching and, if it does, call that method. This gives you a chance to respond to this event without having to subclass UIApplication.
In iPhone applications, developers also frequently use the app delegate as a kind of top-level object. Since you don't usually subclass UIApplication, most developers keep their global application data in the app delegate.
A delegate is just an object that implements certain methods (basically callbacks). The NSApplication docs explain what its delegate is supposed to do and what messages it needs to respond to to.
And this isn't instantiation. The snippet you posted above doesn't create anything. It accesses whatever object is set as the application's delegate. [UIApplication sharedApplication] gets the object representing the application, and sending delegate to the application gets its delegate (if any).
to add more to the mix of responses and another point of view, delegates are objects that can (but don't necessarily need to) do work for another object.
So let's say you have objectA, and can assign to it a delegate (let's call it delegateObject).
From objectA's point of view, there are certain bits of work that may need to be done. Depending on the context, the actual work and the results of such work can be different.
So instead of having objectA implementing a method for all these instances, we'll say... let's have another object, delegateObject, do the work... and as long as the results are returned in the proper format, we don't care what delegateObject did to get there.
objectA will first check that delegateObject exists and that delegateObject has implemented a method to do the work asked of it.
To accomplish this, NSObject (which every Cocoa object inherits from) has this method:
- (BOOL)respondsToSelector:(SEL)aSelector
and objectA would do a simple test before sending a message to delegateObject, for example:
if ([delegate respondsToSelector: #selector(someMethod:sender:)])
{
[delegate someMethod:#"stuff" sender:self];
}
and because objectA only sends a message to its delegate if one's been assigned, delegate is not retained by objectA.
if we were to use UITableView as an example, it has a lot of UITableViewDelegate methods. One of them is:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
every time the user touches a row in a table, the UITableView object will first check that there's a delegate, if there's a delegate, it'll then check that the delegate has implemented the above method. If it does, then it'll send the message to the delegate. This method expects no return value, and UITableView will go about its merry way, regardless of what the delegate does. And if there is no delegate that implements that method, then nothing happens.
I think I've understood what that Delegate is supposed to do. If a class conforms to that protocol, it tells the underlying system: "Hey man, I am the UIApplication object's delegate! Tell me what's up, and I may tell you what to do!".
What, if multiple classes implement that? Is that possible? Does that make any sense?
While you could implement multiple classes that conform to the UIApplicationDelegate protocol only one, the first, would receive these messages.
Implementing a protocol to create a delegate is only one part of the equation. That delegate then has to be registered with the code that's generating the messages and these systems generally only support one delegate.
In the case of UIApplication you can change the delegate using the 'delegate' property in the UIApplication shared class but this will replace the original delegate, not add an additional one.
If you need to broadcast UIApplication level messages to other systems then this is functionality you should add to your existing delegate.
You can implement multiple classes that adopt the UIApplicationDelegate protocol, but only one can be the actual delegate at any given time. It's set by [UIApplication sharedApplication].delegate, which is normally set up by the main NIB file by an outlet connection.
Just conforming to the protocol doesn't set your object as the delegate, you need to do that explicitly either in the nib or in code. As already mentioned, only one object can be a delegate at one time. Having multiple delegates may make sense in some cases-- for example if you have a table view that displays two sets of data, you could make two delegate and datasource objects for it, and switch between them as needed. It probably doesn't make sense to do this for the application's delegate though, since the code there is pretty specific.
Keep in mind that sometimes an object will send notifications in addition to calling delegate methods. A lot of time it looks like they're the same thing, since the object will automatically subscribe your delegate to the notification if it includes a certain method signature. The key difference though is that other objects besides the delegate can also subscribe to these notifications, so you can hook them up to multiple objects at once.
As Daniel Dickson stated:
You can implement multiple classes that adopt the UIApplicationDelegate protocol, but only one can be the actual delegate at any given time. It's set by [UIApplication sharedApplication].delegate, which is normally set up by the main NIB file by an outlet connection.
... but know that you can swap these out at runtime if you need to. I recently looked at using this technique as a way of merging two applications developed by different parties that could not share source code or refactor; yet needed to co-locate under a single icon on the device.
My tabBarController-based app has several tabs. Each has a custom viewController class, the only difference being the way the instance is initialized. Is there a way to make interface builder send the different tabs custom init parameters?
Currently I'm doing the initialisation in viewWillAppear, but for a bunch of reasons it would make sense to do it in IB instead of in the code.
Any suggestions?
thanks,
Kelso
Interface Builder creates an archive of objects that is unarchived when you program executes. You can't really tell IB to call particular methods.
If you need to initialize before viewWillAppear: is called, you can do so in awakeFromNib, which is guaranteed to be called after all objects have been loaded and all outlets have been connected to their targets.
If you want to do initialization even earlier, you can do so by overriding initWithCoder: (see the NSCoding protocol for documentation). I don't know if it is documented anywhere, but that is the designated initialized for objects being decoded from an archive.
In all of the above, you won't be able to receive parameters, but in the code you should be able to access whatever you need with some judicious use of global variables. You can also use [[UIApplication sharedApplication] delegate] to get access to your application delegate object.
I don't think there's any way to change what methods are called by the IB runtime when your nib is loaded. If you described what you were trying to accomplish (i.e. why doing the setup in viewDidAppear doesn't work for you), you might get a suggestion of a better way to handle your initialization.