开发者

Variadic function in Objective C that accepts primitives

Right now, i have this:

// .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];

    开发者_Go百科return lImmutableArray;
}

but the comparison to nil is incorrect because ints are not objects. Using NSNumbers would defeat the purpose for me as i am trying not to allocate the objects outside of this method.

what to do?


This problem also exists in C. If you're using integers like this, you can't use a sentinel (as you've discovered). What most people do is define the first argument as the size instead. So your prototype might looks something like:

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

The obvious problem with this kind of design is that the compiler can't check it. If you make a mistake with the size, you could be in trouble, but this is the same exact kind of problem you'd have in C even if you passed an array of ints or something like that. It's up to the caller to make sure that size is correct.

Another solution would be to have an illegal int as the sentinel. So, choose something like MAX_INT or whatever. When you find that, stop reading the list. Again, however, you can't really get the compiler to warn about that...


Ok for those of you bewildered by primitives as VA_ARGS... here is a cononical answer for all y'all. Here I present a Category on CALayer that takes a variable length "list" of CAConstraintAttribute(s), and applies them to the layer..

@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

Now, adding layer constraints is simplified to...

[layer addConstraintsRelSuper:kCAConstraintMaxX, kCAConstraintHeight, NSNotFound];

NSLOG layer.constraints ➞ "[MaxX = superlayer.MaxX]", "[Height = superlayer.Height]"

...from what previously would have been many HUNDREDS of characters.

And for the sake of completeness.. here is my Macro for CAConstRelSuper...

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

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜