Функция Variadic в Objective C, которая принимает примитивы - PullRequest
2 голосов
/ 29 ноября 2010

Прямо сейчас у меня есть это:

// .h
- (NSArray *)createNumberArrayWithInts:(NSInteger)firstArg, ...
    NS_REQUIRES_NIL_TERMINATION;

// .m
- (NSArray *)newNumberArrayWithInts:(NSInteger)firstArg, ... {
    NSMutableArray *lCreatedArray = [NSMutableArray alloc];

    va_list args;
    va_start(args, firstArg);
    for (NSInteger arg = firstArg; arg != nil; arg = va_arg(args, NSInteger)) {
        NSNumber *lTempNumberObject = [[NSNumber alloc] initWithInteger:arg];
        [lCreatedArray addObject:lTempNumberObject];
        [lTempNumberObject release];

    }
    va_end(args);

    NSArray *lImmutableArray = [[NSArray alloc] initWithArray:lCreatedArray];
    [lCreatedArray release];

    return lImmutableArray;
}

, но сравнение с nil неверно, потому что целые не являются объектами.Использование NSNumbers лишило бы меня цели, поскольку я стараюсь не размещать объекты вне этого метода.

что делать?

Ответы [ 2 ]

4 голосов
/ 29 ноября 2010

Эта проблема также существует в C. Если вы используете целые числа, подобные этой, вы не можете использовать часовой (как вы обнаружили). Большинство людей вместо этого определяют первый аргумент как размер. Так что ваш прототип может выглядеть примерно так:

- (NSArray *)createNumberArrayWithInts:(NSUInteger)length, ...

Очевидная проблема с этим типом дизайна заключается в том, что компилятор не может его проверить. Если вы ошиблись с размером, у вас могут возникнуть проблемы, но это точно такая же проблема, как и в C, даже если вы передали массив целых или что-то в этом роде. Звонящий должен убедиться, что размер правильный.

Другим решением было бы использование нелегального int в качестве сторожа. Итак, выберите что-то вроде MAX_INT или что-то еще. Когда вы найдете это, прекратите читать список. Опять же, однако, вы не можете заставить компилятор предупреждать об этом ...

3 голосов
/ 15 октября 2012

Ладно, для тех из вас, кого изумляют примитивы, как VA_ARGS ... вот кононический ответ для всех вас. Здесь я представляю категорию на CALayer, которая принимает переменную длину «список» CAConstraintAttribute (s) и применяет их к слою

@interface CALayer (VariadicConstraints)
- (void)addConstraintsRelSuper:(CAConstraintAttribute)first,...; 
/* REQUIRES NSNotFound termination */
@end

@implementation CALayer (VariadicConstraints)
- (void)addConstraintsRelSuper:(CAConstraintAttribute)first,...{ /* REQUIRES NSNotFound termination */
   va_list args;   va_start(args, first);
   for (NSUInteger arg = first;  arg != NSNotFound;
                   arg = va_arg( args, NSUInteger))
   { [self addConstraint:CAConstRelSuper(arg)]; }
   va_end(args);
}
@end

Теперь добавление ограничений слоя упрощено до ...

[layer addConstraintsRelSuper:kCAConstraintMaxX, kCAConstraintHeight, NSNotFound];

NSLOG layer.constraints ➞ "[MaxX = superlayer.MaxX]", "[Высота = суперслой. Высота]"

... из того, что раньше было бы сотнями персонажей.

И ради полноты .. вот мой Макрос для CAConstRelSuper ...

#define CAConstRelSuper(attr) [CAConstraint constraintWithAttribute: \
attr relativeTo:@"superlayer" attribute:attr]
...