The Pensive Programmer
Objective-C Protocols and Delegates
My earlier article about building a currency formatter for a UITextField generated a few comments and
some confusion about how to use delegates in iPhone programming. In this article/tutorial I hope to clear up any confusion and tie it back to using the the currency formatter with the UITextField.
So now we have all we need to create a stubbed out version of our UITextFieldDelegate protocol implementation:
The @interface line is where we tell the compiler that we are implementing the UITextFieldDelegate with this class. Keep in mind that it doesn't have to be a separate class like here, and could instead be the controller or any other class where you think the delegate methods should be implemented. I like doing a separate class since it makes the delegate easy to reuse and keeps the code modularized.
Since we have not yet provided any implementation, if we took this above code as is and made it the delegate of a UITextField the text field would work the same way it does without a delegate attached. Since this post is not about the implementation of the currency format delegate I'm going to point readers to my previous post on implementation and move on to how to use the delegate.
You'll notice a bit of object management code to make sure that we properly allocate and release the delegate when we are done with it. The key line in all of the controller code is:
It is here where we tell the text field to user our delegate and call our implementation of the protocol methods.
I hope that this clears up some of the issues people were having while trying to use my text field currency formatter. The code above should mostly work as is since I took it from a working program and pared it down for the post. If there are any copy and paste issues they shouldn't be too hard to correct.
转自:http://www.thepensiveprogrammer.com/2010/05/objective-c-protocols-and-delegates.html
What Is A Protocol?
The Apple documentation on a protocol can be found here. The documentation summarizes that:Protocols declare methods that can be implemented by any class. Protocols are useful in at least three situations:The situation that we are interested in is the first one that allows methods to be declared that others are expected to implement. In this situation protocols are very similar to Java and C# interfaces. In our particular case Apples UIKit framework provides a protocol for use with the UITextField. This protocol is conveniently named UITextFieldDelegate. Defined in this protocol are 7 optional methods that a program can implement to change the behavior of a UITextField. Keep in mind that Apple has only provided the skeleton of the method and not any actual implementation. The implementation is left up to the programmer to implement for their specific needs. In our case we only need to implement 2 of the methods.
- To declare methods that others are expected to implement
- To declare the interface to an object while concealing its class
- To capture similarities among classes that are not hierarchically related
1
2
3
|
-
( BOOL )textField:(UITextField
*)textField shouldChangeCharactersInRange:( NSRange )range
replacementString:( NSString
*)string -
( BOOL )textFieldShouldReturn:(UITextField
*)textField |
So now we have all we need to create a stubbed out version of our UITextFieldDelegate protocol implementation:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
//
CurrencyFormatDelegate.h #import
<Foundation/Foundation.h> @interface
CurrencyFormatDelegate : NSObject
<UITextFieldDelegate>{ } //MARK:
- //MARK:
UITextFieldDelegate Methods -( BOOL )textFieldShouldReturn:(UITextField
*)textField; -( BOOL )textField:(UITextField
*)textField shouldChangeCharactersInRange:( NSRange )range
replacementString:( NSString
*)string; @end |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
//
CurrencyFormatDelegate.m #import
"CurrencyFormatDelegate.h" @implementation
CurrencyFormatDelegate //
Dismisses the keyboard when the return button is pressed -( BOOL )textFieldShouldReturn:(UITextField
*)textField{ [textField
resignFirstResponder]; return
NO ; } -( BOOL )textField:(UITextField
*)textField shouldChangeCharactersInRange:( NSRange )range
replacementString:( NSString
*)string{ return
YES ; } @end |
The @interface line is where we tell the compiler that we are implementing the UITextFieldDelegate with this class. Keep in mind that it doesn't have to be a separate class like here, and could instead be the controller or any other class where you think the delegate methods should be implemented. I like doing a separate class since it makes the delegate easy to reuse and keeps the code modularized.
Since we have not yet provided any implementation, if we took this above code as is and made it the delegate of a UITextField the text field would work the same way it does without a delegate attached. Since this post is not about the implementation of the currency format delegate I'm going to point readers to my previous post on implementation and move on to how to use the delegate.
What Is A Delegate?
Once again the Apple documentation is quite good at explaining delegation. In delegation programming one object (in our case the UITextField) relies on another object (the CurrencyFormatDelegate) to provide a certain set of functionality. As the Apple documentation explains, using delegation programming allows the programmer to customize the behavior of framework objects without having to subclass. In turn this allows the programmer to aggregate multiple delegates into one object and extend the functionality of the existing framework. Now, what does all this mean for the currency formatter? In order to get our delegate to execute at the proper time we have to attach it to our UITextField. Assume that we have already defined and linked a UITextField in Interface Builder and we called it currencyTextField. In the controllers viewDidLoad we just need to assign the CurrencyFormatDelegate our UITextFields delegate property.
1
2
3
4
5
6
7
8
9
10
11
12
|
//
TestController.h @class
CurrencyFormatDelegate; @interface
BuyCarViewController : UIViewController { UITextField
*currencyTextField; @private CurrencyFormatDelegate*
currencyFormatDelegate; } @property ( nonatomic ,
retain) IBOutlet
UITextField* currencyTextField; @property ( nonatomic ,
assign) CurrencyFormatDelegate* currencyFormatDelegate; @end |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
|
//
TestController.m #import
"TestController.h" #import
"CurrencyFormatDelegate.h" @implementation
TestController @synthesize
currencyTextField; @synthesize
currencyFormatDelegate; @synthesize
buyCarView, amortizationView; //
MARK: - //
MARK: View Boilerplate - Object Management //
Implement viewDidLoad to do additional setup after //
loading the view, typically from a nib. -
( void )viewDidLoad
{ [ self
setCurrencyFormatDelegate:[[CurrencyFormatDelegate alloc] init]]; [currencyTextField
setDelegate:currencyFormatDelegate]; [ super
viewDidLoad]; } -
( void )viewDidUnload
{ [currencyTextField
setDelegate: nil ]; } -
( void )dealloc
{ [currencyFormatDelegate
release]; [ super
dealloc]; } |
You'll notice a bit of object management code to make sure that we properly allocate and release the delegate when we are done with it. The key line in all of the controller code is:
1
|
[currencyTextField
setDelegate:currencyFormatDelegate]; |
It is here where we tell the text field to user our delegate and call our implementation of the protocol methods.
I hope that this clears up some of the issues people were having while trying to use my text field currency formatter. The code above should mostly work as is since I took it from a working program and pared it down for the post. If there are any copy and paste issues they shouldn't be too hard to correct.
Further Reading
The delegate pattern is a fundamental object oriented design pattern. If you want to know more about the delegate pattern and design patters in general check out Design Patterns.转自:http://www.thepensiveprogrammer.com/2010/05/objective-c-protocols-and-delegates.html