如何在 Objective-C 中创建可变参数方法

问题描述 投票:0回答:4

也许这对你们大多数人来说显然很简单,但是您能否举例说明如何在 C 中创建类似的方法(在 Objective-C 中)和函数来创建像

NSString
stringWithFormat:
NSLog() 这样的函数
.

提醒一下:

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

我想创建类似于

NSString
的方法
stringWithFormat:
NSURL - urlWithFormat

objective-c xcode format variadic-functions null
4个回答
133
投票

这些通常被称为“可变参数函数”(或方法)。

要创建它,只需使用 , ...

end
方法声明,如

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

此时,您可能希望将其包装在类似

printf
的函数中,因为从头开始实现其中一个函数充其量只是尝试。

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

注意使用

NSLogv
而不是
NSLog
;考虑
NSLog(NSString *, ...);
NSLogv(NSString *, va_list);
,或者如果你想要一个字符串;
initWithFormat:arguments:
NSString *


另一方面,如果您不使用字符串,而是使用类似的东西

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

事情变得容易多了。

在这种情况下,不要使用

vprintf
式的函数,而是使用遍历
args
的循环,假设 id,然后像在任何循环中一样解析它们。

- (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);
}

当然,最后一个示例假设 va_args 列表以 nil 结尾。

注意:为了使这项工作成功,您可能必须包含

<stdarg.h>
;但如果没记错的话,它会与 NSLogv 一起包含在内,这意味着它是通过“Foundation.h”下降的,因此也是“AppKit.h”和“Cocoa.h”以及其他一些;所以这应该是开箱即用的。


23
投票
- (void)methodWithFormat:(NSString*)format, ... {
  va_list args;
  va_start(args,format);
  //loop, get every next arg by calling va_arg(args,<type>)
  // e.g. NSString *arg=va_arg(args,NSString*) or int arg=(args,int)
  va_end(args);
}

如果要将变量参数传递给 stringWithFormat:,请使用类似:

NSString *s=[[[NSString alloc] initWithFormat:format arguments:args] autorelease];

12
投票

这里需要提到的是,这里的第一个 NSString 参数是作为 format 来的,另一个是在变量参数中传递的。正确的?因此,在进入 for 循环之前,您需要处理一个参数。

- (NSString *) append:(NSString *)list, ...
{
    NSMutableString * res = [NSMutableString string];
    [res appendString:list];

    va_list args;
    va_start(args, list);
    id arg = nil;

    while(( arg = va_arg(args, id))){
        [res appendString:arg];
    }
    va_end(args);
    return res;
}

- (void) test_va_arg
{
    NSString * t = [self append:@"a", @"b", @"c", nil];
    STAssertEqualObjects(@"abc", t, @"");
}

0
投票

这是GNUStep 的实现

#import <Foundation/Foundation.h>

#define    GS_MAX_OBJECTS_FROM_STACK    128

#define GS_USEIDLIST(firstObject, code...) ({\
  va_list    __ap; \
  unsigned int    __max = GS_MAX_OBJECTS_FROM_STACK; \
  unsigned int    __count = 0; \
  id        __buf[__max]; \
  id        *__objects = __buf; \
  id        __obj = firstObject; \
  va_start(__ap, firstObject); \
  while (__obj != nil && __count < __max) \
    { \
      __objects[__count] = __obj; \
      __obj = va_arg(__ap, id); \
      if (++__count == __max) \
    { \
      while (__obj != nil) \
        { \
          __count++; \
          __obj = va_arg(__ap, id); \
        } \
    } \
    } \
  va_end(__ap); \
  if (__count > __max) \
    { \
      unsigned int    __tmp; \
      __objects = (id*)NSZoneMalloc(NSDefaultMallocZone(),__count*sizeof(id)); \
      va_start(__ap, firstObject); \
      __objects[0] = firstObject; \
      for (__tmp = 1; __tmp < __count; __tmp++) \
    { \
      __objects[__tmp] = va_arg(__ap, id); \
    } \
      va_end(__ap); \
    } \
  code; \
  if (__objects != __buf) NSZoneFree (NSDefaultMallocZone(),__objects); \
})

@interface MyObject : NSObject
- (void)printWithObjects:(id)firstObject, ... NS_REQUIRES_NIL_TERMINATION;
@end

@implementation MyObject

- (void)printWithObjects:(id)firstObject, ... {
    GS_USEIDLIST(firstObject, {
        for (unsigned int i = 0; i < __count; i++) {
            NSLog(@"%@", __objects[i]);
        }
    });
}

@end

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        [[MyObject new] printWithObjects:@"1", @"2", @"3", nil];
    }
    return 0;
}
© www.soinside.com 2019 - 2024. All rights reserved.