Why are some delegate methods not called automatically? - cocoa-touch

Why are some delegate methods not called automatically? I thought that if you used a delegate method that it would be called automatically. But That's not the case as I've found out. For an example see this post

In the case you mentioned, the method didUpdateHeading isn't called because the manager itself hasn't started yet. Basically, your controller is already listening for notifications, but the notifications don't even exist yet because the location manager hasn't been started. As soon as the manager is instructed to begin tracking user location, then the delegate methods will be called.
So in your example, you placed the startUpdatingHeading call inside the method that would be called once your manager is started. So, it never gets called.

To have a delegate method called, you need a delegate. And as the answer to that post said, the code was setting up the delegate inside a delegate method. So, if the delegate is set up inside a method that only runs after the delegate exist, nothing will happen.

Related

Order of NSApplication delegate calls

I'm noticing something strange in my NSApplication delegate callbacks. When I start the app with debugger attached, I see what I expect: applicationDidFinishLaunching: is called first, then applicationDidBecomeActive:
When I run the app without the debugger, I get the calls in the order reversed: applicationDidBecomeActive: is called before applicationDidFinishLaunching:
Is there a reason for this? It makes it very confusing to account for different scenarios based on debugger vs. non-debugger.
[note: testing this is in Mavericks]
The relative order of those delegate methods during launch is not documented, so you should not rely on any particular order.
If you're concerned about some initialization not having been done when -applicationDidBecomeActive: is called, then you should do that initialization in -applicationWillFinishLaunching: rather than in -applicationDidFinishLaunching:. Alternatively, you should do the initialization on demand, such as initializing a property when its value is first requested.

Using Protocols in Objective C to Transfer Data Between Different Objects?

Hey guys, I currently have a root table view which has a toolbar at the bottom and has labels and a refresh button within it, much like the Mail app's toolbar. This root table view controller obtains data from a server by allocating and initializing a DataUpdater class. Within this class are the NSURLConnection delegate methods that are called while communicating with the server.
As you can probably guess, I need to know when certain (delegate) functions are called within the DataUpdater class and the values of the parameters passed to these delegate functions so that I can update the labels on the toolbar accordingly (i.e. Connecting..., Updated, etc).
The problem I am having is determining how to notify the root table view controller of what is going on in these delegate methods. Would I use protocols, if so how? I have been skimming the documentation and don't quite see how I would get this effect. Or would you suggest I implement my program another way?
Thanks in advance!
A protocol is a kind of contract that says: I promise to provide the non-optional methods defined in the protocol, and maybe even the optional ones. It's purpose is like Java interfaces: to work around missing multiple-inheritence.
The delegate pattern in Objective-C normally works like this: you define a protocol, and then in your class, you define a variable like id<MyProtocol> myDelegate; and define a setter and maybe getter (either via normal methods, e.g. - (void)setDelegate:(id<MyProtocol>)aDelegate; or via properties.
Note that the delegate is not retained ! So if you work with a property, you need the assign option, not retain.
Now back in your class, you check whether myDelegate is nil and if not, you can directly call its non-optional methods. If you want to call an optional method, you first need to verify its presence via respondsToSelector:.
So if you decide to use the delegate pattern, you need to define a protocol, add that protocol to your root table view controller, implement the necessary methods there, and make sure to call [foo setDelegate:self]; or something similar to inform your other class that the root table view controller is the delegate. And of course implement the delegate calls in your class.
Edit:
An alternative might be to use NSNotifications, BTW. The advantage of notifications is that you can have multiple objects listen and react to them. The disadvantage is that you cannot (directly) pass values back. For example, you can define a delegate method that asks the delegate whether to do something or not. That's not possible with notifications, it's more like shouting into a room instead of having a one-to-one conversation.
DarkDust's answer about protocols is fine but I would like to add some things to it.
One underlying thing that is often forgotten when it comes to delegation is object ownership. When a program is running it creates a tree of objects. Its root object is the application delegate and for example it owns a navigation controller, which owns the individual view controllers, which own the view and the view owns its subviews and so on.
Often the question comes up: "Why is the delegate not retained, just assigned?" The problem is that if you send a message to a deallocated object the program crashes. So how do you make sure the delegate stays around? The answer is object ownership.
I give you an example: a UITableView and its data source which is the TableViewController which is nothing but a delegate. The TableViewController holds a reference with its view property to the UITableView, so it owns the TableView. That means when the tableView is alive there must also be its parent object present, which is the UITableView's delegate. So there is no danger that the delegate goes away somehow.
In the end it is again all about memory management.
Take home message is: think upfront about object ownership will make your program mode modular, easier to maintain and will lead to a looser coupling between individual objects.

Using NSProgressIndicator inside an NSMenuItem

I'm trying to use a NSProgressIndicator (indeterminate) inside of a statusbar-menu. I'm using an NSView-object as view for the menuitem, and then subviews the progress indicator to display it. But whenever i try to call the startAnimation: for the progress, nothing happens. When i try do the very same thing on a normal NSWindow it works perfectly, just not when inside a menuitem.
I'm new to both cocoa and objective-c so I might've overlooked something "obvious" but I've searched quite a bit for a workaround but without success. I found something about menuitems cant be updated while shown and that you need to use a bordeless window instead. But I have not been able to confirm this in any documentation.
Edit:
Ok, almost works now. When using the setUsesThreadedAnimation: and from a MenuDelegate's menuWillOpen and creating a new thread. This thread runs a local method:
-(void) doWork(NSProgressIndicator*) p{
[p startAnimation:self];
}
This will start the progressindicator on a random(?) basis when opening the menu. If I call startAnimation: directly without going through doWork: (still using a new thread), it never works. Doesn't setUsesThreadedAnimation: make the progress-bar create it's own thread for the animation?
Solved it by using:
[progressIndicator performSelector:#selector(startAnimation:)
withObject:self
afterDelay:0.0
inModes:[NSArray
arrayWithObject:NSEventTrackingRunLoopMode]];
Inside the menuWillOpen:, the problem seems to have been calling startAnimation: before the progressbar was finished drawing itself.
How are you referencing the NSProgressIndicator that is in the view (and the one in the window, for that matter)? For example, do you have a controller class that has IBOutlet's hooked up to the progress indicators? If you are using an IBOutlet, are you sure it's hooked up properly in the nib file?
Also, where and when are you calling startAnimation:? (We need to see some code).
One thing that can sometimes happen is that you forget to hook up an IBOutlet in the nib. Then, when you attempt to tell the object to do something in code at runtime, the IBOutlet is nil, and so what you think is a message being sent to your object is in fact, a message being sent to nil. In other words, it's just ignored, and effectively looks like it's not working.
Provided you do have a (potentially) valid reference to the UI object, the other common issue you'll see is when a developer is trying to send a message to the object at "too early" of a time. In general, init methods are too early in the controller object's lifetime to be able to send messages to user interface objects—those IBOutlet's are still nil. By the time -awakeFromNib is called, IBOutlet's should be valid (provided you hooked them up in IB) and you can then send the message to the UI object.
Have you told it to use threaded animation via -setUsesThreadedAnimation:?

Where do FirstResponder methods come from?

I'm looking at IKImageDemo supplied by Apple, the rotate round-slider is linked to a setRotation: method in the FirstResponder. However, none of the objects in the project seem to HAVE such a method, and yet the code works.
I'm trying copy this into my own project, and MY FirstResponder doesn't have a setRotation: method, so I'm not sure where it lives. Google has been unhelpful...
thanks.
Well, the first responder in the app happens to be an instance of IKImageView. IKImageView responds to the setRotation: selector (which can be seen by passing respondsToSelector:#selector(setRotation:) to any instance of IKImageView), although I cannot find where in documentation it mentions the setRotation: method
First Responder methods aren't magic. What happens when a message is sent to the first responder is that the app's current first responder (this is usually the focused view/control) is asked whether or not it implements the method. If it does, the method is called. If it doesn't, the next responder up the chain is asked, and so on until the top level (the NSApplication instance) is reached. The object must actually implement the method for it to be called, it can't just declare it.
In this case IKImageView implements -setRotation: as a private method. This means that the method is present (which is why the IKImageView accepts the message sent to the First Responder) but its use is not documented or supported. It seems odd that Apple would ship an example using a private method but there you go. It's definitely the case that sometimes methods are accidentally left out of the public headers when their use is supported, however it's generally wise to avoid private methods unless someone from Apple has specifically told you it's OK to use one.
You can generate headers for all methods of an Objective-C object, including private methods, from the binary using class-dump.
IKImageView has a public method -setRotationAngle: which is probably the way to go if you want to change the rotation.
I've found a way of resolving this annoyance. Even in the original Apple example, once you remove the binding for setRotation in the First Responder, you cannot put it back, unless doing this trick: simply use the Attributes Inspector for the First Responder and add a User Defined action "setRotation:" with type "id". Now even the yellow triangle in the First Responder binding for setRotation: in the Apple example disappears, and it shows up also in my own IKImageView instance.

Checking for a valid delegate object before sending it a message

I am trying to implement the delegate Pattern in Objective-C, however I am experiencing a Bad Access exception when invoking the delegate sometimes. It seems this is caused by the delegate being released. Apple does not recommend to retain delegates.
How can I check my delegate if is still valid before trying to send it a message?
If there's a chance that the delegate will get released by the setter, then there's something wrong with your design. You should only set delegates on objects that have a shorter lifespan than the delegate itself. For example, setting a delegate on a subview/controller is fine, because the subview/controller has a shorter lifespan than the caller.
AFAIK, there is no reliable way to detect if an object has been released already.
What Apple means about not retaining delegates is that objects should not retain their delegates because they don't own them. These are only objects that handle messages.
That doesn't mean that you shouldn't retain delegates at all. The object that creates the delegate needs to own it. In the context of non-GC apps this means it should handle the retain and release cycle, and for GC apps, it means that the controller object keeps hold of a pointer to the delegate in an iVar.
without seeing some code or the error message, it is hard to find the root of this problem.
In a photoviewer application I'm using asynchronous http to load images; it happens that the user often dismisses the current view (referenced by my async http object through a delegate) before the http download completed causing a BAD_ACCESS when calling the view controller delegate method. I solved this by setting the .delegate to nil inside the dealloc block of the view controller
I'd like to share my experience also, which is very similar to Nico's one.
I've been working with a modified example of LazyTablesCode, wich is an example that comes direcly from Apple and loads images in a UITableView asynchronously. Communication between the downloader and the view it's made via delegates.
In my code, I had the problem that sometimes the load of the image finishes when the form that should be called through the delegate has been released. I've been forced to add this piece of code inside the code of the viewController (dealloc method):
if (self.nsDictionaryWithObjectsDownloading != nil) {
for (id theKey in self.nsDictionaryWithObjectsDownloading) {
Myobj *downloader = [self.nsDictionaryWithObjectsDownloading objectForKey:theKey];
downloader.delegate = nil;
}
}
It seems that these lines are solving the problem. Anyway It would be very appreciated opinions about if it's a good solution or not or even about memory issues when doing downloader.delegate = nil;
Thanks and greetings,