NSMutableDictionary с UIButton * как ключи - разработка iPhone

Я новичок в разработке 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 * в качестве ключей? Может ли кто-нибудь указать мне, почему я получаю эту ошибку? Спасибо всем,

аа

Ответ 1

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

[NSValue valueWithNonretainedObject:myButton].

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

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

for (NSValue* nsv in myDict) {
    UIButton* b = (UIButton*)[nsv nonretainedObjectValue];
    ...
}

Ответ 2

Из Документы Apple:

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

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

Ответ 3

У меня классный трюк.

Я передал указатель на 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];
}

Ответ 4

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