iPhone Dev - Delegate or event? - iphone

In many situations, such as making the keyboard go away when the use clicks done, there are two options: set the text field's delegate to self, and adopt the UITextFieldDelegate protocol, and then use the method
- (BOOL)textFieldShouldReturn:(UITextField *)textField;
to resignFirstResponder and return YES. But you can also
addTarget:self
action:#selector(myMethod:)
forControlEvent:UIControlEventDidEndOnExit];
or something like that, using the did end on exit event, and then in the method, [sender resignFirstResponder]. So what is the best option in situations like these: the delegate, or the event?

The quick rule of thumb is that delegates are supposed to answer the question of "should I?" on behalf of the object they are a delegate for. Events, on the other hand, are broadcast afterward to let listeners know that something has happened.
In your case, while you could call [sender resignFirstResponder] in response to the event, you're mixing metaphors by doing this. Your delegate should have already made the decision to hide the keyboard (or not) and the event being broadcast is merely to let all the other components know that they keyboard hid.

If you are going to be paired with one other class, where the real type of that class may vary, then it makes a lot of sense to formalize that pairing into a protocol and a delegate arrangement.
If the information you want to send is targeted at a broader set of objects, then it starts to make more sense to use notifications - though now you have somewhat obscured what information is being passed by the notification as there's no central definition for what to expect.
Both are about an equal load to work with - with a delegate you have to set yourself and then remember to unset yourself before you are deallocated. You have to do the same thing with notifications, remember to start listening and then unsubscribe before you are deallocated.
Also, you should try as much as possible to make sure you send notifications out on the main thread as the notices get sent on the same thread they started from. Same goes for delegate methods, it's not very kind to call a delegate method from some other mystery thread!

The delegate makes your objects more reusable they are an adapter that lets any object interact with the defined behaviors of that object and use the object. I would say delegates should be adopted by the object responsible for keeping the state of and defining behavior to actions that will occur in the object that it is using. Events should be used for any other objects that are intersted in particular action that the object that has the protocol does (so objects not responsible for keeping the state of the object that defines the protocol).
For example: A view controller using a textfield will adopt its protocol to dismiss the keyboard and any other behaviors that can occur for a textfield, maybe another controller will do some animation when the keyboard is dismissed, so it will register to the textfield as an event in order to receieve the event of the keyboard being dismissed.

Related

What does obj.delegate=self mean?

What does it actually mean to set the delegate of a textfield?
For example: txtField.delegate = self
"In short, that you are receiving calls from the txtField. You are setting the object 'self' as the delegate for txtField."
"That means that your 'txtField' will receive events from itself
These two answers essentially mean the same thing. But seemingly contradictory. But the first makes more sense to me. I can see why a beginner gets confused, I've been there!
Basically one is the caller one is the receiver Think of it as a chef in a kitchen call his assistant to cut up some onions. In this particular case, txtField is the chef, "self" is the assistant. txtField orders self "Do this, this and this!" Like it or not the assistant has to oblige cuz he has wife and kids to feed. :)
It means that self will be the recipient of certain method calls that are made in response to actions on the text field.
In short, that you are receiving calls from the txtField. You are setting the object 'self' as the delegate for txtField.
Delegating is a programming pattern that is widely used in Objective-C.
The basic idea is let an object delegate some tasks to another object. For example, your UITextField object delegate some tasks to your view controller. In this case, your UITextField object becomes a delegating object, and the view controller the delegate of the UITextField object. The delegating object sends certain messages to its delegate in order to get necessary information, or to notify certain events, etc.
That means that your 'txtField' will receive events from itself (kind of a weird example, maybe a larger source code section could be provided?)
For some of its methods, the textfield (any object in a class using the delegation pattern) is going to try to call some other object to so that that object can customize some of the textfield's behaviors. The object that the textfield will try call is called it's delegate. The delegate is initially set to nil, so, by default, no customization happens.
If a class has a line of code like: textfield.delegate = self; then it says that this object in this class wants to get called to handle the textfield's customization for certain of the textfield's defined delegate methods.
It means the actual class where 'txtField.delegate =self' is called will receive callsbacks from events. This is often a convenient way to do things.

Can someone please explain delegates in objective-c?

I have been using Objective-C for a while and pretty much understand most of its features. However, the concept of delegates eludes me. Can someone please give a succinct and easy to comprehend explanation of what delegates are, how they are used in the iPhone SDK, and how I can best make use of them in my own code?
Thank you!
There are a couple main reasons to use delegates in Objective-C, which are subtly different:
Enhancing the base functionality of a framework class. For example, a UITableView is pretty boring on its own, so you can give it a delegate to handle the interesting bits (creating table cells, adding text to section headers, what have you). This way, UITableView never changes, but different table views can look and act very differently.
Communicating to parent objects in your dependency hierarchy. For example, you may have a view with a button that the user may push to do something that affects other views. The view will have to send a message to its parent view, or perhaps the view controller, so that it can create or destroy or modify other views. To do this you'd pass the parent object into your view, most likely through a protocol, as a weak reference (in Objective-C, an assign property). The view could then send any message declared in the protocol to the parent, or delegate, object.
This approach need not involve views. For example NSURLConnection passes event back to its delegate, which may be the object that created it, using this mechanism.
Essentially, all a delegate is, is an object that accepts feedback from another object. Put simply, when stuff happens to an object, it tells its delegate (assuming it has one).
For instance, lets say I have a UIViewController with a UITextView placed in the middle of the view. I set up my UIViewController to be the delegate of the UITextView. Then, when certain actions are performed on the text view (begin editing, text changes, end editing, etc), it tells it's delegate so it can do whatever logic it needs to do, like spell checking every time characters change, or dismissing the keyboard when it receives a return key press.
Delegate methods perform a similar function to callback functions in C.
Hope that makes sense :)
Best and simple concept I got from a Lynda.com Tutorial was: When you set a Delegate it means you have been given work to do. So, if you want to use methods that are written in a protocol method, you must implement them by searching in the Delegate Class Reference and using them. I hope it helped.
By the way, Delegates are excellents. They are your friends. They have been made to make your life as a programmer much easier.

iPhone first responders

I am confused about the iPhone responder chain. Specifically, in the iPhone event handling guide http://developer.apple.com/iPhone/library/documentation/iPhone/Conceptual/iPhoneOSProgrammingGuide/EventHandling/EventHandling.html, we have the following:
The first responder is the responder object in an application (usually a UIView object) that is designated to be the first recipient of events other than touch events.
But UIView is a subclass of UIResponder. And the UIResponder class reference says this:
- (BOOL)canBecomeFirstResponder
Return Value
YES if the receiver can become the first responder, NO otherwise.
Discussion
Returns NO by default. If a responder object returns YES from this method, it becomes the first responder and can receive touch events and action messages. Subclasses must override this method to be able to become first responder.
I am confused by the apparent contradiction. Can anyone clear it up for me?
For what it's worth, I did set up a simple view-based application, and call canBecomeFirstResponder and isFirstResponder on its view. Both returned NO.
The nomenclature can be confusing. Instead of "first responder" think of it as "initial event target" i.e. the object that is the first responder becomes the initial target for all events. In some APIs this is also called the "focus" although in the Apple APIs that is usually reserved to describe windows.
At any given time, there is only one first-responder/intial-event-target in the app. Only individual objects/instances can become a first-responder/intial-event-target. Classes can merely define if their instance have the ability to become a first-responder/intial-event-target. A class need only provide the ability to become the app's first-responder/intial-event-target if it make sense to do so. For example, a textfield obviously needs the ability to trap events so that it can use those event to edit itself. By contrast, a static label needs no such capability.
Whether a particular class inherits from NSResonder has no bearing on whether the class (or a specific instance of the class) will let itself be set as the first-responder/intial-event-target. That ability comes solely from the instances' response to the canBecomeFirstResponder message. The same instance can refuse to be the first-responder/intial-event-target under one set of conditions and then allow it later when conditions change. Classes can of course hardwire the status if they wish.
In other words, first-responder/intial-event-target is a status of a particular instance at a particular time. The first-responder/intial-event-target is like a hot potato or a token that is handed off from instance to instance in the UI. Some classes refuse to grab the hot potato at all. Some always do and others grab it sometimes and ignore it others.
What this means is that the basic UIView is not able to become first responder - it doesn't do anything with motion events, editing-menu messages, etc.
Some UIView subclasses (like UITextView) are able to become first responder, and you can write your own UIView subclass that does so too.

How to receive application wide events with multiview application

I am developing an iPhone application with multiviews (Nav controller), but i like to receive an event if user touches in any view of the view. I understand it can be done by subclassing application delegate? If that's true how can i do it? My requirement is, i like to receive an event as soon as user touches any where in any view within my application.
Thanks for your help and time.
Your reference to subclassing UIApplication will work. Read down through the comments and it covers a somewhat quirky IMO way to implement it (by having the AppDelegate be a subclass of UIApplication). Myself, I would create a separate class to be the UIApplication subclass, rather than having the app delegate do both jobs, but I see the merit of either way.
That said, this is a very large and unusual stick and may suggest a design failure. What problem are you solving with this?
A way to do it is to use a Singleton class (which acts as an observer/mediator), which the application is an example of, in which you have viewControllers subscribe to when they are intersted in the touch events of a certain view. When the touch occurs the Singleton class is informed of the event as a result it informs all subscribers to the event of the event.
Here is an example
#interface MyEventClass
{
-(void)TouchEventDidOccur;
-(void)subscribeToTouchEvent:(id)delegate selector(selector):sel
}
Above is the singleton class
now this is an example of what the view touchesBegan method might look like
-(void)touchesBegan...
{
[[MyEventClass sharedInstance] TouchEventDidOccur];
}
and how one would subscribe to the event
[[MyEventClass sharedInstance] subscribeToTouchEvent:self selector:#selector(receiveTouchEvent:)]
hope this helps
What's wrong with using notifications? If you have disconnected classes across your application, it's trivial to have them listen for a particular notification, then have your views or view controllers post that notification when a touch event happens. All of the observers will take action on the notification.

Invoking a method on a delegate after delay, from an object at the end of it's lifetime

I have a modal view controller that creates core data changes in it's own context, and when I click done, it saves the changes (that dispatches the merge changes notification), notifies the delegate and dismisses.
My problem is that I need the delegate to receive the message after my main context has merged with the changes of the editing context. I want the delegate call to take place on the next run loop but I'm having problems with object lifetimes. I've thought of the following:
Make call to [delegate performSelector:withObject:afterDelay:] however it seems that that message is not recognised. My delegate conforms to the NSObject protocol but that doesn't include the perform selector with delay.
Create a method in my view controller: informDelegateWithObject: that calls the delegate method, and call that method after a delay. I.e. [self performSelector:#selector(informDelegateWithObject:) withObject:.. afterDelay:..]. This could work, however, as my view controller is being dismissed, if the delay is several seconds then it would have been released from memory and wouldn't that cause a crash when it comes to invoking?
Create an instance of NSInvocation. I have thought about this, however, what is the lifetime of this object? If I create it using [NSInvocation invocationWithMethodSignature:] then wouldn't the NSInvocation object be autoreleased, and not be around for the next run loop? Let alone several seconds. And as my modal view controller is being dismissed and released, I can't store the invocation object in my view controller.
Any suggestions?
You should merge contexts into the delegate.
Say that you press Save into you modal controller: you will send a myViewController:didFinishSaving: to the delegate.
This delegate into myViewController:didFinishSaving: implementation will save, merge and dismiss the modal view controller.
I hope I have understood your problem.
Bye! :)
You might look at Apple's Core Data Books tutorial which works along the lines that muccy describes. Saving happens after the modal view is dismissed and control is returned to the parent view controller. The parent contains the update code and fires notifications required to merge changes (whether that happens in the delegate or elsewhere).
To question #1: performSelector:withObject:afterDelay: is defined in the NSObject class, not the NSObject protocol. Any object you are using is probably an instance of NSObject. You are probably referring to a compiler warning resulting from static type checking. (Technically, it's possible for an object that conforms to the NSObject protocol to not be an NSObject; NSProxy is one example. But any object you normally use will be an NSObject.) You can ignore this warning (in Objective-C, you can try to send any message to any object). Or, if you want, you can cast it to either id (which allows you to send any message without any warnings) or NSObject *.
To question #2: "if the delay is several seconds then it would have been released from memory" No, the documentation for performSelector:withObject:afterDelay: says "This method retains the receiver and the anArgument parameter until after the selector is performed."
You can also declare your delegate like this:
NSObject <MyClassDelegateProtocol> *delegate;
Then your delegate will also be an NSObject that conforms to your protocol.