I have the following code that updates the value of a textfield with the current time. My question is: Why do you send nil as the sender at the bot开发者_开发知识库tom part of the code? [self showCurrentTime:nil];
CurrentTimeViewController.m
- (IBAction)showCurrentTime:(id)sender
{
NSDate *now = [NSDate date];
static NSDateFormatter *formatter = nil;
if(!formatter) {
formatter = [[NSDateFormatter alloc] init];
[formatter setTimeStyle:NSDateFormatterShortStyle];
}
[timeLabel setText:[formatter stringFromDate:now]];
}
...
- (void)viewWillAppear:(BOOL)animated
{
NSLog(@"CurrentTimeViewController will appear");
[super viewWillAppear:animated];
[self showCurrentTime:nil];
}
Because normally when action handlers are called, they pass the object that initiated the call to the method, like a UIButton
, or UISegmentedControl
. But, when you want to call the method from your code, and not as the result of an action, you cannot pass a human as sender
, so you pass nil
.
Also, the - (IBAction)
indicates that this method can be connected to an event via the Interface Builder
by dragging a Touch Up Inside
(or touch down outside/etc) event from a button (or any other control that has some sort of event) to the File's Owner
and selecting thumbTapped:
.
For example:
UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
button.tag = 1001;
[button addTarget:self action:@selector(thumbTapped:) forControlEvents:UIControlEventTouchUpInside];
When the touch is released (and the touch is still inside the button), will call thumbTapped:
, passing the button
object as the sender
- (IBAction)thumbTapped:(id)sender {
if ([sender isKindOfClass:[UIButton class]] && ((UIButton *)sender).tag == 1001) {
iPhoneImagePreviewViewController *previewVC = [[iPhoneImagePreviewViewController alloc] initWithNibName:@"iPhoneImagePreviewViewController" bundle:nil];
[self.navigationController pushViewController:previewVC animated:YES];
[previewVC release];
} else {
[[[[UIAlertView alloc] initWithTitle:[[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleDisplayName"]
message:@"This method was called from somewhere in user code, not as the result of an action!"
delegate:self
cancelButtonTitle:@"OK"
otherButtonTitles:nil] autorelease] show];
}
}
IBAction methods, in their most common form, take a single sender argument. When invoked by the system, they pass the control that triggered the action as the sender parameter. If you're going to call the method directly, you'll need to provide a sender. Since this method isn't being invoked by a control that's just been interacted with by the user, nil is used.
I actually think that calling actions directly isn't a good pattern to follow. Having a method with the tag IBAction implies "This method is invoked in response to user action" and that's an important bit of context to be able to depend on when working within that method. If code is going to call the method directly that idea's been violated.
Usually I think it's better to do something like this:
- (void)updateTime:(NSDate *)date {
static NSDateFormatter *formatter = nil;
if(!formatter) {
formatter = [[NSDateFormatter alloc] init];
[formatter setTimeStyle:NSDateFormatterShortStyle];
}
[timeLabel setText:[formatter stringFromDate:date]];
}
- (IBAction)showCurrentTime:(id)sender {
[self updateTime:[NSDate date]];
}
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
[self updateTime:[NSDate date]];
}
It's because you need to send something, since the signature of the method you're calling takes an argument.
The :(id)sender
is commonly seen in button press actions. When you connect a button in a nib to a method in your view controller, it will check to see if it can take an argument. If it does, the "sender" will point to the instance of the UIButton
that was created in the nib.
This is also true for programmatic button creation, and many other cases where you send in selectors.
The specifcation for the showCurrentTime function has 1 argument named sender. If you called the function without sending the ID of an object the call would be invalid.
Nil is used instead of NULL in objective-c and it is purely being sent to satisfy the specification of the function you are calling.
As the function does not actually use the argument within the body it does not actually matter what object you send to the function.
精彩评论