views:

1164

answers:

3

I have a method that accepts a sender and is called with a UIbutton. How do I get that object to casted into a UIImageView? Basically how do I re-use the code for the button.

- (IBAction)startClick:(id)sender { 
    button.animationImages = [NSArray arrayWithObjects:
                                       [UIImage imageNamed:@"Pic_1.png"],
                                       [UIImage imageNamed:@"Pic_2.png"],
                                       [UIImage imageNamed:@"Pic_3.png"],
                                       nil];
    [button setAnimationRepeatCount:1];
    button.animationDuration = 1;
    [button startAnimating];
}
A: 

I seem to think you would have done this.

UIButton *button = (UIButton*) id;
// then do all you button code here.

This should work. Otherwise, it might be better to change the function to

 (IBAction)startClick:(UIButton *)theButton

This way you want have to cast the button.

John Ballinger
The latter suggestion probably won't work. IB action methods always have return type "IBAction" (which is defined as void) and the parameter is of type id.
Quinn Taylor
+3  A: 

My first response is that it's probably a mistake to do so. UIButton and UIImageView are distinct subclasses of UIView (and UIButton is a subclass of UIControl) so the only things they have in common are UIView methods. If sender is really a UIButton, treating it as a UIImageView is likely to result in errors, such as "unrecognized selector sent to instance" and the like.

In general, a cleaner solution is to create a separate method that is the action for a UIImageView. (Unlike Java, Objective-C and Cocoa prefer to not shoehorn UI response code into a single method based on the event type — rather, you organize the code logically based on the operation that needs to happen.)

If you must call this method from both buttons and image views, you can separate the logic like this:

- (IBAction) startClick:(id)sender {
  if ([sender isKindOfClass:UIButton]) {
    ...
  }
  else if ([sender isKindOfClass:UIImageView]) {
    ...
  }
}
Quinn Taylor
A: 

Do you have an outlet for your button? Is the button the only UI element which will send -startClick:? If so, then write the action method like this:

- (IBAction)startClick:(id)sender { 
 NSParameterAssert(sender == self.startClickButton);
 if (sender == self.startClickButton) {
  UIButton *button = self.startClickButton;
  [...]
 }
}

If you don't have an outlet/property for the button, you can test the sender's class, and cast if appropriate.

- (IBAction)startClick:(id)sender { 
 NSParameterAssert([sender isKindOfClass: [UIButton class]]);
 if ([sender isKindOfClass: [UIButton class]]) {
  UIButton *button = (UIButton *)sender;
  [...]
 }
}

Finally, it is permissible (at compile time) to send any message to an id typed value. (You'll get an exception at runtime if the receiver doesn't respond to that message.) You cannot, however, use dot syntax.

So if you know that the sender is always a button, you can write your method without casting at all. You'll have to use messages send syntax instead of dot syntax.

[button setAnimationImages: [NSArray ...]];
[button setAnimationDuration: 1];

This is important to understand - dot syntax is equivalent to message send syntax - it isn't mystical.

Jim Correia