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]
精彩评论