Comedy option:
- (NSString *)format:(id)first, ... {
NSUInteger argCount = 0;
BOOL prevPercent = NO;
for (NSUInteger i = 0; i < [self length]; ++i) {
unichar c = [self characterAtIndex:i];
if (prevPercent && c != '%')
++argCount;
prevPercent = c == '%';
}
NSMutableArray *argArr = [NSMutableArray new];
va_list args;
va_start(args, first);
for (NSUInteger i = 0; i < argCount; ++i)
[argArr addObject:va_arg(args, id)];
va_end(args);
switch (argCount) {
case 0: return [NSString stringWithFormat:self, first];
case 1: return [NSString stringWithFormat:self, first, argArr[0]];
case 2: return [NSString stringWithFormat:self, first, argArr[0], argArr[1]];
// ...
}
}
Only supports NSObject arguments, obviously. If you actually wanted to do this approach you'd want to do a better job of parsing the format string and use a more cleverer way of storing the args.
Or, for the completely insane approach that probably doesn't actually work (on top of being entirely unportable):
- (NSString *)format:(id)first, ... {
NSUInteger argCount = ...;
va_list args;
va_start(args, first);
void *argList = malloc(sizeof(id) * (argCount + 1));
memcpy(argList, (void*)&first, sizeof(id));
memcpy(argList + sizeof(id), &va_arg(args, void *), sizeof(id) * argCount);
va_end(args);
NSString *ret = [[NSString alloc] initWithFormat:self arguments:argList];
free(argList);
return ret;
}