NSDictionary: метод, определенный только для абстрактного класса. Мое приложение разбилось
Мое приложение разбилось после того, как я вызвал addImageToQueue. Я добавил initWithObjects: forKeys: count: но мне это не помогло.
Terminating app due to uncaught exception 'NSInvalidArgumentException',
reason: '*** -[NSDictionary initWithObjects:forKeys:count:]:
method only defined for abstract class.
Define -[DictionaryWithTag initWithObjects:forKeys:count:]!'
мой код
- (void)addImageToQueue:(NSDictionary *)dict
{
DictionaryWithTag *dictTag = [DictionaryWithTag dictionaryWithDictionary:dict];
}
@interface DictionaryWithTag : NSDictionary
@property (nonatomic, assign) int tag;
- (id)initWithObjects:(id *)objects forKeys:(id *)keys count:(NSUInteger)count;
@end
@implementation DictionaryWithTag
@synthesize tag;
- (id)initWithObjects:(id *)objects forKeys:(id *)keys count:(NSUInteger)count
{
return [super initWithObjects:objects forKeys:keys count:count];
}
@end
Ответы
Ответ 1
Вы подклассифицируете NSDictionary? Это не обычная вещь в Cocoa -land, которая может объяснить, почему вы не видите ожидаемых результатов.
NSDictionary - кластер классов. Это означает, что вы никогда не работаете с экземпляром NSDictionary, а скорее с одним из своих частных подклассов. См. Описание Apple кластера классов здесь. Из этого документа:
Вы создаете и взаимодействуете с экземплярами кластера, как и любой другой класс. Однако за кулисами, когда вы создаете экземпляр открытого класса, класс возвращает объект соответствующего подкласса на основе метода создания, который вы вызываете. (Вы не хотите и не можете выбрать фактический класс экземпляра.)
В сообщении вашего сообщения вам сообщается, что если вы хотите подклассифицировать NSDictionary, вам необходимо реализовать для него собственное бэкэнд-хранилище (например, написав хэш-таблицу на C). Это не просто просит вас объявить этот метод, он просит вас написать его с нуля, самостоятельно обрабатывая хранилище. Это потому, что подклассификация кластера классов прямо так же, как будто вы хотите предоставить новую реализацию для работы словарей. Как я уверен, вы можете сказать, что это важная задача.
Предполагая, что вы определенно хотите подклассифицировать NSDictionary, лучше всего написать свой подкласс, чтобы он содержал нормальный NSMutableDictionary как свойство и использовать его для обработки вашего хранилища. В этом руководстве показан один из способов сделать это. На самом деле это не так сложно, вам просто нужно передать необходимые методы в свой словарь.
Вы также можете попробовать использовать ассоциативные ссылки, которые "имитируют добавление переменных экземпляра объекта в существующий класс". Таким образом, вы можете связать NSNumber с вашим существующим словарем для представления тега, и не требуется никакого подкласса.
Конечно, вы могли бы просто иметь tag
как ключ в словаре и хранить значение внутри него, как и любой другой ключ словаря.
Ответ 2
Из fooobar.com/questions/305621/... это то, что я сделал, чтобы сделать подкласс работ NSDictionary. Я просто объявляю NSDictionary как переменную экземпляра моего класса и добавляю еще несколько необходимых методов. Он называется "Composite Object" - спасибо @mahboudz.
@interface MyCustomNSDictionary : NSDictionary {
NSDictionary *_dict;
}
@end
@implementation MyCustomNSDictionary
- (id)initWithObjects:(const id [])objects forKeys:(const id [])keys count:(NSUInteger)cnt {
_dict = [NSDictionary dictionaryWithObjects:objects forKeys:keys count:cnt];
return self;
}
- (NSUInteger)count {
return [_dict count];
}
- (id)objectForKey:(id)aKey {
return [_dict objectForKey:aKey];
}
- (NSEnumerator *)keyEnumerator {
return [_dict keyEnumerator];
}
@end
Ответ 3
Я просто сделал небольшой трюк.
Я не уверен, что это лучшее решение (или даже хорошо это делать).
@interface MyDictionary : NSDictionary
@end
@implementation MyDictionary
+ (id) allocMyDictionary
{
return [[self alloc] init];
}
- (id) init
{
self = (MyDictionary *)[[NSDictionary alloc] init];
return self;
}
@end
Это сработало для меня.