2014-10-27 3 views
0

Я пытаюсь научить себя объективному c. Я привык (~ 10 лет назад) быть довольно хорош с C++, поэтому я решил, что это не должно быть слишком сложно, но после стольких лет работы с python и различными языками математического программирования я довольно ржавый по указателям и тому подобное, которые, как я полагаю, вероятно, что вызывает это.Почему я получаю ошибки «непризнанного селектора»?

В любом случае, я продолжаю получать непризнанные ошибки селектора для методов, которые определенно существуют в документации и выводах отладки xcode (что я не очень хорошо знаю, поэтому, возможно, это неправильно) показывает, что эти объекты инициализированы. Я попытался сделать следующий пример как можно меньше. Вот класс я написал:

// Graph.h 

#import <Foundation/Foundation.h> 

@interface Graph : NSObject 

@property NSMutableSet *myObjects; 
- (id)initWithNumElements:(int)total; 
- (NSMutableSet *)addOneMore:(NSMutableSet *)vertices; 
- (NSMutableSet *)addTo:(NSMutableSet *)R from:(NSMutableSet *)P; 

@end 

и его реализации:

// Graph.m 

#import "Graph.h" 

@implementation Graph 

// Put numbers 0, ..., total - 1 into the objects of self 
- (id)initWithNumElements:(int)total { 
    self = [super init]; 
    if (self) { 
     NSMutableSet *objects = [[NSMutableSet alloc] init]; 
     for (int i=0; i<total; i++) { 
      [objects addObject:[NSNumber numberWithInt:i]]; 
     } 
     _myObjects = objects; 
    } 
    return self; 
} 

// If possible, add one of the objects of self to set 
- (NSMutableSet *)addOneMore:(NSMutableSet *)set { 
    NSMutableSet *allObjects = [self.myObjects copy]; 
    for (id elt in set) { 
     [allObjects removeObject:elt]; 
    } 
    //[allObjects minusSet:set]; 
    return [self addTo:[set copy] from:allObjects]; 
} 

// If possible, add one object from P to R 
- (NSMutableSet *)addTo:(NSMutableSet *)R from:(NSMutableSet *)P { 
    if ([P count] == 0) { 
     return R; 
    } 
    id v = [P anyObject]; 
    [R addObject:v]; 
    return R; 
} 

@end 

и я проверяю его с помощью следующего кода:

// main.m 

#import <Foundation/Foundation.h> 
#import "Graph.h" 

int main(int argc, const char * argv[]) { 
    @autoreleasepool { 
     Graph *G = [[Graph alloc] initWithNumElements:6]; 
     NSMutableSet *results = [G addOneMore:[[NSMutableSet alloc] init]]; 
     NSLog(@"%@", results); 
    } 
    return 0; 
} 

(я знаю, логически это код не имеет смысла. Он упрощен до глупости от чего-то, что когда-то делало лишь небольшое количество смысла.)

Я получаю ошибку

2014-10-27 11:19:14.936 Test[1469:303] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSSetI addObject:]: unrecognized selector sent to instance 0x100108a20' 

и Xcode указывает мне точно на линии "[R AddObject: v];". Но материал отладки говорит, что R является NSMutableSet *, а v является _NFCSNumber *, в чем проблема? Насколько я могу судить, это должно быть справедливо.

Записанная строка "// [allObjects minusSet: set];" также генерирует непризнанную ошибку селектора, которая не возникает, когда я заменяю ее циклом for, который находится над ним. Опять же, эта строка должна быть действительной, насколько я могу судить, я не могу понять, что здесь не так.

ответ

7

В addOneMore: линия

NSMutableSet *allObjects = [self.myObjects copy]; 

не назначает изменяемый набор для allObjects, а непреложный NSSet. Если вам нужна измененная копия, вам нужно использовать mutableCopy, даже если исходный контейнер (набор, массив, словарь) является изменяемым вариантом. copy возвращает неизменяемые экземпляры.

Вы получаете нераспознанную ошибку селектора, поскольку addObject: не является допустимым селектором для неизменяемого набора.

+0

Удивительно, что это исправлено. У меня есть два следующих вопроса: 1) Поскольку копия предоставляется NSObject, я просто предположил, что полученный класс будет таким же, как и объект, который вы копировали. Учитывая какой-то другой класс, как можно посмотреть, вернет ли «копия» тот же тип или нет? 2) Почему ничего не жаловалось, когда я назначил что-то, что не является NSMutableSet для переменной NSMutableSet? – Jim

+1

'copy' - удобный метод, который делегирует реальную работу' copyWithZone: ', которая является частью' NSCopying'. Его возвращаемый тип 'id' является частью этого удобства быть на' NSObject' и, к сожалению, неизбежен. Как правило, 'copy' будет возвращать тот же класс, который вы вызываете, кроме контейнеров, которые имеют как неизменные, так и изменяемые варианты. В этом случае он всегда будет возвращать неизменяемую версию. Что касается (2), вы не получили предупреждение из-за типичного типа возврата id. Компилятор не знает реальный тип и, следовательно, не может вас предупредить. –

Смежные вопросы