You can use NSArray
and NSNumber
literal syntax to get something like that. Here's how you call it:
[self setGradientColorComponents:@[
@0.0f, @0.8f, @0.0f, @1.0f, // green
@1.0f, @1.0f, @0.0f, @1.0f, // yellow
@0.9f, @0.0f, @0.0f, @1.0f // red
] withLocations:@[
@0.0f, @0.5f, @1.0f
]];
Here's how you implement it:
- (void)setGradientColorComponents:(NSArray *)components withLocations:(NSArray *)locations {
NSUInteger count = components.count;
CGFloat componentFloats[count];
for (NSUInteger i = 0; i < count; ++i) {
componentFloats[i] = [components[i] floatValue];
}
count = locations.count;
CGFloat locationFloats[count];
for (NSUInteger i = 0; i < count; ++i) {
locationFloats[i] = [locations[i] floatValue];
}
CGColorSpaceRef rgb = CGColorSpaceCreateDeviceRGB();
CGGradientRef gradient = CGGradientCreateWithColorComponents(rgb, componentFloats, locationFloats, count);
CGColorSpaceRelease(rgb);
// do whatever with gradient
CGGradientRelease(gradient);
}
On the other hand, you can use a variadic function. Since a variadic function can only have one variadic list of arguments, you must mix the locations with the color components. You must also mark the end of the list somehow. Here's how you call it:
[self setGradient:
0.0, 0.0, 0.8, 0.0, 1.0, // location 0.0, color green
0.5, 1.0, 1.0, 0.0, 1.0, // location 0.5, color yellow
1.0, 0.9, 0.0, 0.0, 1.0, // location 1.0, color red
-1.0
];
This is more dangerous, because it's up to you to make sure that you only pass doubles to the function, and it's up to you to make sure you pass the -1.0
sentinel at the end of the list. I recommend sticking with my first solution (using NSArray
and NSNumber
literals). That said, here's how you implement the variadic solution:
- (void)setGradient:(CGFloat)location0, ... {
size_t count = 0;
va_list ap;
va_start(ap, location0);
// Note that when you pass a float as a variadic argument, the compiler promotes it to double.
double f = location0;
while (f >= 0.0 && f <= 1.0) {
++count;
f = va_arg(ap, double);
}
va_end(ap);
NSAssert(count % 5 == 0, @"number of arguments is %lu which is not a multiple of 5", (unsigned long)count);
count /= 5;
CGFloat locations[count];
CGFloat components[4 * count];
va_start(ap, location0);
f = location0;
for (size_t i = 0; i < count; ++i) {
locations[i] = (CGFloat)f; f = va_arg(ap, double);
components[i * 4 + 0] = (CGFloat)f; f = va_arg(ap, double);
components[i * 4 + 1] = (CGFloat)f; f = va_arg(ap, double);
components[i * 4 + 2] = (CGFloat)f; f = va_arg(ap, double);
components[i * 4 + 3] = (CGFloat)f; f = va_arg(ap, double);
}
va_end(ap);
CGColorSpaceRef rgb = CGColorSpaceCreateDeviceRGB();
CGGradientRef gradient = CGGradientCreateWithColorComponents(rgb, components, locations, count);
CGColorSpaceRelease(rgb);
// do whatever with gradient
CGGradientRelease(gradient);
}