A question of objective-C protocol
I try to learn protocol of objective C.
I write two files, the first one is FirstViewController.h, and in which there is a protocol "print". I declare FirstViewCont开发者_开发技巧roller class in successViewController with the delegate method "print". The question is why the console output is "C". Why I can not get the "B" output? Why the protocol method did not perform?#import <UIKit/UIKit.h>
#import "FirstViewController.h"
@interface successViewController : UIViewController <FirstViewControllerDelegate> {
}
@end
#import "successViewController.h"
#import "FirstViewController.h"
@implementation successViewController
- (void)viewDidLoad {
FirstViewController *firstViewController= [[FirstViewController alloc] init];
firstViewController.delegate=self;
NSLog(@"C");
[super viewDidLoad];
}
-(void) print{
NSLog(@"B");
}
@end
#import <Foundation/Foundation.h>
@class FirstViewController;
@protocol FirstViewControllerDelegate <NSObject>
- (void) print;
@end
@interface FirstViewController : NSObject {
id <FirstViewControllerDelegate> delegate;
}
@property (nonatomic, assign) id <FirstViewControllerDelegate> delegate;
@end
#import "FirstViewController.h"
@implementation FirstViewController
@synthesize delegate;
@end
Because you never call the print
method. Where were you expecting it to be called?
Objective-C protocols allow you to specify that a class is capable of performing certain actions. In your example, the successViewController
is declared FirstViewControllerDelegate
, meaning it is capable of handing the duties required by FirstViewController
of its delegate. It is more of a programming contract between classes, one that can be verified by the compiler.
As a side note, classes in Objective-C should always start with a capital letter, methods should always start lowercase. Your FirstViewController
follows this rule, but the successViewController
does not.
You need to call the method you want to use.
[successViewController print];
You never call the delegates print
method. A delegate can not read your mind and automagically call stuff. Lets take a small example how how delegates are supposed to work.
Assume we have a class called Delay
, the only thing it do is to wait for a time when start
is called, and then tell it's delegate that it has waited. Optionally the delegate can tell the Delay
how long to wait, if the client do not care, a 1 second delay is assumed.
Some rules:
- First argument of all delegate methods should be the sender itself, never have delegate methods with no arguments.
- Delegate method name should include one of the words:
will
- if method is called before something unavoidable occurs. Exampleapplication
Will
Terminate:
did
- if method is called after something has occurred. ExamplescrollView
Did
Scroll:
should
- if the method return a BOOL to signal if something should occur. ExampletextField
Should
Clear:
- Name the method to tell what has occurred, not what you expect the delegate to do.
- Only exception is if the client is expected to return something, then that something should be part of the name. Example:
tableView:
editingStyle
ForRowAtIndexPath:
- Only exception is if the client is expected to return something, then that something should be part of the name. Example:
Here is the simple definition and implementation. Notice that I do not even check if the delegate has been set, since calling methods on nil
is just ignored anyway.
// Delay.h
@protocol DelayDelegate;
@interface Delay : NSObject {
@private
id<DelayDelegate> _delegate;
}
@property(nonatomic, assign) id<DelayDelegate> delegate;
-(void)start;
@end
@protocol DelayDelegate <NSObject>
@required
-(void)delayDidComplete:(Delay*)delay;
@optional
-(NSTimeInterval)timeIntervalForDelay:(Delay*)delay;
@end
// Delay.m
@interface Delay
@synthesize = delegate = _delegate;
-(void)start {
NSTimeInterval delay = 1.0;
if ([self.delegate respondsToSelector:@selector(timeIntervalForDelay:)]) {
delay = [self.delegate timeIntervalForDelay:self];
}
[self performSelector:@selector(fireDelay) withObject:nil afterDelay:delay];
}
-(void)fireDelay {
[self.delegate delayDidComplete:self];
}
@end
精彩评论