NSMutableDictionary с UIButton * в качестве ключей - разработка для iPhone - PullRequest
10 голосов
/ 12 мая 2010

Я новичок в разработке для iPhone, и у меня есть вопрос, на который может быть очень простой ответ. Я пытаюсь добавить кнопки в представление, и эти кнопки связаны с пользовательским классом, который я определил. Когда я добавляю кнопки в представление, я хотел бы знать, какому классу соответствуют эти кнопки. Это потому, что когда я нажимаю кнопку, мне нужно получить некоторую информацию о классе, но получатель сообщения - другой класс. Я не смог найти информацию об ошибке, которую я получаю в Интернете. У меня проблема в том, что я пытаюсь создать NSMutableDictionary, где ключи имеют тип UIButton *, а значения имеют мой собственный тип:

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

Конечно, sourceButtonMap определяется в классе и инициализируется в функции init как sourceButtonMap = [[NSMutableDictionary alloc] init];

Ошибка, которую я получаю при попытке добавить пару ключ-значение:

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

Это происходит потому, что я не могу сохранить UIButton * как ключи? Может кто-нибудь указать мне, почему я получаю эту ошибку? Спасибо всем,

аа

Ответы [ 4 ]

16 голосов
/ 07 июля 2010

Один из способов, который я нашел, - использовать конструкцию NSValue для использования в качестве ключа. Для создания этого используйте:

[NSValue valueWithNonretainedObject:myButton].

Похоже, здесь предостережение о том, что если кнопка является сборщиком мусора, ключ будет содержать недопустимую ссылку.

Вы можете снова получить ссылку на UIButton при циклическом просмотре словаря следующим образом:

for (NSValue* nsv in myDict) {
    UIButton* b = (UIButton*)[nsv nonretainedObjectValue];
    ...
}
3 голосов
/ 12 мая 2010

С Apple Docs :

Ключ копируется (используя copyWithZone :; ключи должны соответствовать протокол NSCopying).

UIButton не соответствует протоколу NSCopying, поэтому его нельзя использовать в качестве ключа в NSDictionary

2 голосов
/ 07 декабря 2011

UIButtons имеют свойство description, которое можно использовать в качестве ключа словаря:

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
2 голосов
/ 15 мая 2011

У меня есть крутой трюк для этого.

Я приведу указатель к int (так как на самом деле это все указатель) и сохраню его в NSNumber. Использование NSNumber в качестве ключа решает эту проблему и имеет смысл, потому что кому нужно хранить копию кнопки в словаре? Для меня более логично хранить копию информации указателя.

Если я вам нравлюсь, вы, вероятно, также включите этот макрос в макрос. Как то так:

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

Тогда это немного чище для использования в коде ...

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];
}
...