Отсутствует страж в методе отправки - PullRequest
10 голосов
/ 02 января 2012

Я хочу создать подкласс NSMutableArray и должен переопределить метод -initWithObjects:.

а как позвонить [супер ххх];?

- (id) initWithObjects:(id)firstObj, ... {
    [super initWithObjects:firstObj]; // Error: Missing sentinel in method dispatch
    // Error: The result of a delegate init call must be immediately returned or assigned to "self"

}

Спасибо.

Ответы [ 5 ]

46 голосов
/ 21 января 2012

Тогда сообщение «отсутствующий дозорный» относится к отсутствующему нулевому завершению. На самом деле, согласно Wikipedia со шрифтами всех знаний:

Имя nil, который завершает список параметров переменной длины в Objective-C

также: Sentinel узел, объект для представления конца структуры данных также: значение Sentinel, значение, используемое для завершения цикла также: в сетевых протоколах, таких как Bisync, значения часового индикатора указывают, где начинаются и заканчиваются кадры

10 голосов
/ 02 января 2012

Вы не можете. Как обсуждено в документации для NSArray:

Возможно, вы захотите реализовать инициализатор для вашего подкласса, который подходит для резервного хранилища, которым управляет подкласс. NSArray класс не имеет назначенного инициализатора, поэтому ваш инициализатор нужен вызывать только метод init из super. NSArray класс принимает Протоколы NSCopying, NSMutableCopying и NSCoding; если ты хочешь экземпляры вашего собственного подкласса, созданные путем копирования или кодирования, переопределите методы в этих протоколах.

Таким образом, вы можете назначить self = [super init]; и добавить объекты из вашего инициализатора в результирующий объект. Действительно, из-за способа реализации NSArray вызов любого метода -initWith… может вернуть экземпляр другого NSArray подкласса.

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

2 голосов
/ 02 января 2012

Создание подклассов. Классы коллекции не так уж и сложны - если вы используете крошечный трюк (см. Также: cocoawithlove ).

Подкласс - это отношение "есть" в объекте-ориентированный дизайн.Но есть также отношения «есть», то есть оболочки.

Если бы вы попытались создать подкласс NSArray, используя чистое отношение is-a, я думаю, это было бы довольно сложно, так каквам придется управлять памятью на уровне C.

Но если вы добавите отношение has-a - или: создадите обёртку - в то же время, вы можете легко выполнить подкассировку: просто создайте свой собственный массивкласс есть член регулярного NSArray.Теперь переопределите его метод путем переадресации вызовов на объект-член.Я показал это в этом посте, где я просто добавляю объекты, которые проходят определенный тест .

Но вы увидите, что я не реализовал методВы говорили правильно, но я поднимаю ошибку.Причина в том, что этот метод - это метод с переменным числом аргументов, в котором есть переменное число объектов, которые вы можете передать, и чтобы справиться с этим, вам нужно немного поработать. У cocoawithlove есть отличная статья об этом.

Для вас - если использовать этот трюк - это может выглядеть как

- (id) initWithObjects:(id)firstObj, ... {

    if (self = [super init]) {
        _realArray = [[NSMutableArray alloc] initWithCapacity:1];
    }

    va_list args;
    va_start(args, firstObj);
    for (id obj = firstObj; obj != nil; obj = va_arg(args, id))
    {
        [self.realArray addObject:obj];
    }
    va_end(args);
    return self;
}
2 голосов
/ 02 января 2012

Подклассы NSArray / NSMutableArray не работают как подклассы большинства классов. NSArray - это кластер классов, см. примечания по подклассам из NSArray документации.

Теперь, для вашего конкретного вопроса, подклассификация va_list методов немного сложнее, есть несколько способов справиться с этим. «Самым безопасным» было бы обработать ваш va_list в NSArray и передать его в другой метод, который имел дело с тем, что вы хотели. Другой, немного менее переносимый, немного хакерский способ - создать новый список va_list в стеке, через который он будет проходить.

    id __unsafe_unretained * stack = (typeof(stack))calloc(numOfObjects, sizeof(id));
    //filloutStack
    [super initWithObjects:*stack, nil];
    free(stack);
0 голосов
/ 02 января 2012

Попробуйте

self = [super initWithObjects:firstObj,nil];
...