NSMutableDictionary with UIButton* as keys - iPhone development
Asked Answered
M

4

10

I'm new to iPhone development and I have a question that may have a very simple answer. I am trying to add buttons to a view and these buttons are associated with a custom class that I defined. When I add the buttons to the view, I would like to know what class these buttons correspond to. This is because when I press the button, I need to get some information about the class, but the receiver of the message is another class. I couldn't find information about an error that I'm getting on the web. The problem I have is that I'm trying to create an NSMutableDictionary where the keys are of type UIButton* and the values are of my custom type:

   // create button for unit
   UIButton* unitButton = [[UIButton alloc] init];
   [sourceButtonMap setObject:composite forKey:unitButton];

Of course, the sourceButtonMap is defined in the class and initialized in the init function as sourceButtonMap = [[NSMutableDictionary alloc] init];

The error I get when I try to add the key-value pair is:

*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** -[UIButton copyWithZone:]: unrecognized selector sent to instance 0x3931e90'

Is this happening because I can't store UIButton* as keys? Can anyone point me why I'm getting this error? Thank you all,

aa

Marylandmarylee answered 12/5, 2010 at 15:38 Comment(0)
P
16

One way I found was to use construct an NSValue to use as the key. To create the that use:

[NSValue valueWithNonretainedObject:myButton].

The caveat here seems to be that if the button is garbage collected, the key will hold an invalid reference.

You can get the reference to the UIButton again while looping through the Dictionary like so:

for (NSValue* nsv in myDict) {
    UIButton* b = (UIButton*)[nsv nonretainedObjectValue];
    ...
}
Peart answered 7/7, 2010 at 18:28 Comment(1)
I am also facing the same problem.Can you plaese elaborate how to implement this trick.I tried doing this:- but the app is getting crashed. NSDictionary *catPassdict=[NSDictionary dictionary]; [catPassdict setValue:[NSValue valueWithNonretainedObject:catAppButton] forKey:@"btn"];Seay
F
3

From Apple docs:

The key is copied (using copyWithZone:; keys must conform to the NSCopying protocol).

UIButton does not conform to the NSCopying protocol and so you cannot use it as a key in NSDictionary

Foretop answered 12/5, 2010 at 15:44 Comment(1)
That's what I thought, so do you have any suggestion on how to solve this problem? Given a UIButton, I need to obtain the custom class that button represents. If I can't use a dictionary, there has to be another way to do this. I can't use an array because several UIButtons can refer to the same object. Is there a way to give the button the id of the class that represents? Or something similar?Marylandmarylee
D
2

I've got a cool trick for this.

I cast the pointer to an int (since thats all a pointer really is) and store it in an NSNumber. Using the NSNumber as a key solves this problem and makes sense fundementally because who cares about storing a copy of the button in the dictionary? It makes more sense to me to store a copy of the pointer's info.

If your like me, you'll probably wrap that bit up into a macro as well. Something like this:

#define BOX_AS_NUM(_ptr_) [NSNumber numberWithInt:(int)_ptr_]

Then it's a little cleaner to use in code...

NSDictionary* btnMap = [NSDictionary dictionaryWithObjectsAndKeys:some_obj, BOX_AS_NUM(some_btn), nil];
-(IBAction)someBtnAction:(id)sender
{
    SomeObj* obj = [btnMap objectForKey:BOX_AS_NUM(sender)];
    [obj doCoolStuffBecuaseIWasJustClicked];
}
Darien answered 15/5, 2011 at 4:29 Comment(1)
and a cool trick for you: use the built-in mark-up provided in the form instead of html-tags.Minster
S
2

UIButtons have a description property that can be used as a dictionary key:

NSMutableDictionary *myDictionary = [[NSMutableDictionary alloc] initWithCapacity:1];
UIButton *myButton = [[UIButton alloc] initWithFrame:CGRectMake(0.0f, 0.0f, 10.0f, 10.0f)];
id myObject;
[myDictionary setObject:myObject forKey:myButton.description];

// somewhere else in code
id myLookedUpObject = [myDictionary objectForKey:myButton.description];
// do something with myLookedUpObject
Sheridansherie answered 7/12, 2011 at 16:58 Comment(2)
If there's more than one UIButton being used as keys in the dictionary, is there some guarantee that each will have a unique, unchanging value for its description property value? (I tried taking this approach and setting the description property value myself, but it's read-only.)Uncrowned
I used this solution with multiple UIButton and It works fine. In my case, no custom description is needed.Scene

© 2022 - 2024 — McMap. All rights reserved.