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

发布于 2024-10-14 12:24:05 字数 436 浏览 5 评论 0原文

也许这对你们大多数人来说显然很简单,但是您能否举例说明如何在 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

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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

你的他你的她 2024-10-21 12:24:05

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

要创建它,只需使用 , ...结束您的方法声明,如此时

- (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);,或者如果你想要一个字符串; NSString * 上的 initWithFormat:arguments:


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

+ (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 结尾。

注意:为了使这项工作正常进行,您可能必须包含;但如果没记错的话,它会与 NSLogv 一起包含在内,这意味着它是通过“Foundation.h”下降的,因此也是“AppKit.h”和“Cocoa.h”以及其他一些;所以这应该是开箱即用的。

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.

筱果果 2024-10-21 12:24:05
- (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];
- (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);
}

If you want to pass the variable arguments to stringWithFormat:, use something like:

NSString *s=[[[NSString alloc] initWithFormat:format arguments:args] autorelease];
泛滥成性 2024-10-21 12:24:05

这里需要提到的是,这里的第一个 NSString 参数作为格式,另一个是在变量参数中传递的。正确的?因此,在进入 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, @"");
}

One thing to mention here is that, the first NSString parameter here comes as format, and the other are passed in the variable argument. right? So before entering the for loop, you have one parameter to handle.

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

这是 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;
}

Here is GNUStep's implementation

#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;
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文