Search code examples
objective-cxcodeformatvariadic-functionsnull

How to create variable argument methods in Objective-C


Maybe this will be obviously simple for most of you, but could you please give an example how to create similar methods (in Objective-C) and functions in C to create functions like NSString's stringWithFormat:, or NSLog().

Just to remind:

[NSString stringWithFormat:@"example tekst %i %@ %.2f", 122, @"sth", 3.1415"];
NSLog(@"account ID %i email %@", accountID, email);

I'd like to create the similar to NSString's method stringWithFormat:, NSURL - urlWithFormat.


Solution

  • What these are called, generally, is "variadic functions" (or methods, as it were).

    To create this, simply end your method declartion with , ..., as in

    - (void)logMessage:(NSString *)message, ...;
    

    At this point you probably want to wrap it in a printf-like function, as implementing one of those from scratch is trying, at best.

    - (void)logMessage:(NSString *)format, ... {
      va_list args;
      va_start(args, format);
      NSLogv(format, args);
      va_end(args);
    }
    

    Note the use of NSLogv and not NSLog; consider NSLog(NSString *, ...); vs NSLogv(NSString *, va_list);, or if you want a string; initWithFormat:arguments: on NSString *.


    If, on the other hand, you are not working with strings, but rather something like

    + (NSArray *)arrayWithObjects:(id)object, ... NS_REQUIRES_NIL_TERMINATION;
    

    things get a lot easier.

    In that case, instead of a vprintf-style function, use a loop going through args, assuming id as you go, and parse them as you would in any loop.

    - (void)logMessage:(NSString *)format, ... {
      va_list args;
      va_start(args, format);
    
      id arg = nil;
      while ((arg = va_arg(args,id))) {
      /// Do your thing with arg here
      }
    
      va_end(args);
    }
    

    This last sample, of course, assumes that the va_args list is nil-terminated.

    Note: In order to make this work you might have to include <stdarg.h>; but if memory serves, this gets included in connection with NSLogv, meaning it comes down by way of "Foundation.h", therefore also "AppKit.h" and "Cocoa.h", as well as a number of others; so this should work out of the box.