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.

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:
  • 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
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.
?
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

你可能感兴趣的:(The Pensive Programmer)