4

It's great to be able to addTarget on a UIButton. I only wish there was some sneaky way I could attach state to the UIButton so that when the target method is invoked, I could magically pull that state (any id) from the sender.

Something like:

[button shoveMyObjectInThere:foo];
[button addTarget:self action:@selector(touchyTouchy:) forControlEvents:UIControlEventTouchUpInside];

Followed by:

-(void) touchyTouchy:(id) sender {
    UIButton button = (UIButton*)sender;
    id foo = [button getByObjectBack];
    // do something interesting with foo
}

Would be great if UIButton had an 'id context' property where developers could shove stuff, but that doesn't seem to be the case. Objective-C is a very dynamic language though, so I wonder if there is some sneaky way I can add method or fields to an object at runtime?

David Blevins
  • 19,178
  • 3
  • 53
  • 68

4 Answers4

5

You could try making an associative reference

#import <objc/runtime.h>

objc_setAssociatedObject(id object, void *key, id value, objc_AssociationPolicy policy); 
objc_getAssociatedObject(id object, void *key);
Berik
  • 7,816
  • 2
  • 32
  • 40
Rich
  • 1,082
  • 7
  • 11
0

What about something like setValue:forKey:, a part of the Key-Value coding feature of Objective-C?

fbrereto
  • 35,429
  • 19
  • 126
  • 178
  • Gave that a whirl and docs and my experimentation seem to indicate that is only for setting existing fields/accessors. – David Blevins Jan 06 '11 at 01:28
  • Doesn't seem possible to add new member data using KVC. See [Why is my object not key value coding-compliant?](http://stackoverflow.com/q/11491957/1804403) – Skotch May 30 '13 at 21:06
0

So I just did a quick test and found some interesting results.

UIButton *button = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[button setTitle:@"Hello" forState:UIControlStateNormal];
[button addTarget:self action:@selector(buttonClicked:) forControlEvents:UIControlEventTouchUpInside];
button.frame = CGRectMake(100, 100, 100, 100);
[self.window addSubview:button];

// ...

- (void)buttonClicked:(id)sender {
    NSLog(@"button clicked %@", [sender class]);
}

This prints: button clicked UIRoundedRectButton

So it seems like this should be possible... Truth be told, I ran into some problems subclassing UIButton to get the full example working but this seems promising. :)

donkim
  • 13,119
  • 3
  • 42
  • 47
  • This answer does not appear to be related to the question. You have not added any context to the UIButton that can be pulled out in `buttonClicked:` – Skotch May 30 '13 at 21:08
0

The official solution is to use the "tag" property:

[self.someMutableArray addObject:foo];
button.tag = self.someMutableArray.count - 1;

[button addTarget:self action:@selector(touchyTouchy:) forControlEvents:UIControlEventTouchUpInside];

Then:

-(void) touchyTouchy:(id) sender {
    UIButton button = (UIButton*)sender;
    id foo = self.someMutableArray[button.tag];
    // do something interesting with foo
}

In most situations you'd use an enum or constant for the tag, but an array is obviously more flexible.

Abhi Beckert
  • 32,787
  • 12
  • 83
  • 110