Подтвердить что ты не робот

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
4b9b3361

Ответ 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

Это сработало для меня.