Использование класса в качестве ключа в NSDictionary - PullRequest
37 голосов
/ 08 апреля 2009

Я пишу контекстную «фабрику», которая будет поддерживать словарь объектов-преобразователей / действующих объектов, которые наследуются от некоторого класса Converter. Этот класс имеет метод:

- (Class)classResponsibility

Или что-то похожее, такое, что класс StringConverter будет реализовывать метод следующим образом:

- (Class)classResponsibility {
    return [NSString class];
}

Затем, чтобы сохранить этот конвертер в словаре, я надеялся сделать что-то вроде:

[converters setValue:stringConverter forKey:[stringConverter classResponsibility]];

Но компилятор жалуется, что тип "Class" является недопустимым типом параметра для аргумента 2 метода setValue: forKey:. Я хотел избежать установки ключа в качестве имени класса («NSString»), но если это лучшее решение, то я пойду с ним.

Ответы [ 7 ]

98 голосов
/ 20 апреля 2009

Вы используете setValue:forKey:, который принимает NSString с в качестве ключей. Вы должны использовать setObject:forKey: вместо этого. Объект класса (указатели на объекты класса могут передаваться как тип Class) является полноценным объектом Objective-C (объект класса является экземпляром его мета-класса, и вы можете использовать все методы NSObject в объект класса; узнайте больше о мета-классах здесь ), чтобы их можно было использовать везде, где используются объекты.

Другое требование к ключам словаря заключается в том, что они поддерживают копирование (т. Е. Имеют метод copyWithZone:. Поддерживают ли объекты класса этот метод? Фактически, так и есть. Класс NSObject определяет метод класса +copyWithZone:, чья документация прямо говорит, что она "позволяет использовать объект класса в качестве ключа к объекту NSDictionary". Я думаю, что это ответ на ваш вопрос.

30 голосов
/ 06 ноября 2009

Другой вариант - использовать [NSValue valueWithNonretainedObject:yourObjectHere] для создания ключа из чего-то отличного от строки. Я столкнулся с аналогичной проблемой, и я хотел использовать объект CoreData в качестве ключа и что-то еще в качестве значения. Этот NSValue метод работал отлично, и я считаю, что это было его первоначальное намерение. Чтобы вернуться к исходному значению, просто позвоните nonretainedObjectValue

4 голосов
/ 08 апреля 2009

-setValue:forKey: задокументировано для принятия NSString в качестве второго параметра. Вам придется использовать NSStringFromClass() и NSClassFromString() в качестве адаптеров.

3 голосов
/ 23 августа 2011

В то время как объект Class делает совершенно хороший ключ в NSDictionary, стоит упомянуть NSMapTable, который смоделирован после NSDictionary, но обеспечивает большую гибкость в отношении того, какие типы объектов подходят для использования в качестве ключей и / или значений, задокументировано для поддержки слабых ссылок и произвольных указателей.

3 голосов
/ 08 апреля 2009

Я искал setObject: forKey : метод вместо setValue: forKey :. Подпись метода для setObject: forKey: принимает (id) в качестве обоих типов параметров и подходит гораздо лучше.

1 голос
/ 23 апреля 2009

У меня была похожая ситуация с тем же сообщением об ошибке:

[tempDictionary setObject:someDictionary forKey:someClass];

Все, что я сделал, это внедрил протокол NSCopying в someClass:

- (id)copyWithZone:(NSZone *)zone
{
    id copy = [[[self class] allocWithZone:zone] init];
    [copy setId:[self id]];
    [copy setTitle:[self title]];
    return copy;
}

Я думаю, что происходило то, что была сделана копия someClass для использования в качестве ключа, но, поскольку мой объект не знал, как копировать себя (производная от NSObject, он у него есть copyWithZone в суперклассе) он отказался.

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

[После этого я вижу, что вы хотите сохранить класс как ключ. Я оставляю это там, потому что я бы сэкономил много времени, если бы нашел свой ответ, когда искал SO. Я не нашел ничего подобного.]

0 голосов
/ 21 марта 2017

Вы можете использовать классы как ключи NSDictionary, например:

@{
    (id)[MyClass1 class] : @1,
    (id)[MyClass2 class] : @2,
    (id)[MyClass3 class] : @3,
    (id)[MyClass4 class] : @4,
};

Или даже так:

@{
    MyClass1.self : @1,
    MyClass2.self : @2,
    MyClass3.self : @3,
    MyClass4.self : @4,
};
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...