Почему я получаю нераспознанные ошибки селектора?

Я пытаюсь научить себя объективному-с. Раньше (~ 10 лет назад) я неплохо разбирался в С++, поэтому я решил, что это не должно быть слишком сложно, но после стольких лет использования 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, который находится над ним. Опять же, насколько я вижу, эта строка должна быть действительной, я не могу понять, что здесь не так.


person Jim    schedule 27.10.2014    source источник


Ответы (1)


В addOneMore: строка

NSMutableSet *allObjects = [self.myObjects copy];

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

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

person Steve Madsen    schedule 27.10.2014
comment
Круто, это исправило. У меня есть два дополнительных вопроса: 1) Поскольку копия предоставляется NSObject, я просто предположил, что результирующий класс будет таким же, как объект, который вы копировали. Учитывая какой-то другой класс, как узнать, вернет ли копия тот же тип или нет? 2) Почему что-то не жаловалось, когда я присваивал переменную NSMutableSet чему-то, что не является NSMutableSet? - person Jim; 28.10.2014
comment
copy — это удобный метод, который делегирует реальную работу copyWithZone:, который является частью NSCopying. Его возвращаемый тип id является частью удобства использования NSObject и, к сожалению, неизбежен. Как правило, copy возвращает тот же класс, для которого вы его вызываете, за исключением контейнеров, которые имеют как неизменяемые, так и изменяемые варианты. В этом случае он всегда будет возвращать неизменяемую версию. Что касается (2), вы не получили предупреждение из-за общего типа возврата id. Компилятор не знает настоящий тип и поэтому не может вас предупредить. - person Steve Madsen; 28.10.2014