【问题标题】:How to write a function or macro for "oneOf" ... casting in variadics?如何为“oneOf”编写函数或宏......在可变参数中进行转换?
【发布时间】:2011-02-07 11:01:06
【问题描述】:

注意 - 使用可变参数,Phix 在下面提供了一个超级解决方案。但是,当与整数一起使用时,它会发出编译器警告,因为您将它们转换为 id,并且它不适用于例如浮点数。

问题——如何编写一个从列表中选择一项的工具?理想情况下,关于列表中的项目/对象/任何内容的类型应尽可能灵活。

示例用法:

NSInteger openingMap = [utilities oneOf:1, 2, 3, 7, 8];

initialAngle =oneOf(1.25, 1.75, 1.95, 2.00, 2.01);

self.spaceShipNickName =oneOf(@"Blaster",@"Blitzen",@"Stardancer",@"Quantum");

self.chassisProperty = oneOf(titanium, neutronium, unavailablium);

[fireworksLayer paintStars:oneOf(blue,green,white) howMany:oneOf(20,25,50)];

[trump chooseDefaultSuite:oneOf(diamonds,hearts,clubs,spades)];

// normally have a few explosions, but, occasionally have a huge display...
explosionCount = oneOf( 2,2,2,3,4,1,28,3,3,3,70 );

请注意,一些示例是整数、一些枚举、一些 NSString 等。同样,如果一个工具可以处理不同的类型,那将是最令人印象深刻的。 (而不是一个相关的组,比如... oneOfIntegers、oneOfStrings、oneOfObject 等等。)

不用说,要选择随机项目,只需使用...
= arcrandom() % 项目数

您可以使用Objective C 方法或类、c 函数或某种宏系统、NSMutableArray 的类别扩展或块——或其他任何东西。 它应该尽可能灵活,以便在典型 iOS 或 Mac 项目中的任何地方广泛使用......有什么想法吗?

【问题讨论】:

  • 好的..我认为这个问题不适合这里...阅读常见问题解答#2...但是如果您真的希望人们只是为了“挑战”而回答这个问题,请开始赏金,然后看看你得到了多少答案......

标签: iphone objective-c xcode ios macros


【解决方案1】:
#define NUMARGS(...)  (sizeof((id[]){__VA_ARGS__})/sizeof(id))
#define ONEOF(...)  (oneOf(NUMARGS(__VA_ARGS__), __VA_ARGS__))

id oneOf(int numargs, ...) {
    va_list ap; 
    va_start(ap,numargs);
    int i = arc4random() % numargs;
    id val = nil;
    do {
        val = va_arg(ap, id);
    } while (i--);
    va_end(ap);
    return val; 
}

用法:

NSLog(@"%@", ONEOF(@"Blaster",@"Blitzen",@"Stardancer",@"Quantum"));
NSLog(@"%d", ONEOF( 2,2,2,3,4,1,28,3,3,3,70 ));

请注意,两者都有效,但后者会引发一些编译器警告。

【讨论】:

  • 警告是“初始化从整数生成指针而不进行强制转换” - 你可以通过编写第二个宏来避免它,每个 'id' 替换为 'int'(或任何你喜欢的类型)。如果 Objective-C 有像 C++ 这样的模板会更容易:/
【解决方案2】:

我会把它作为一个类别放在 NSArray 上(警告 - 此代码未经测试,可能有一个错误!)

@interface NSArray (one_of)
  - (id)anyObject;
@end

@implementation NSArray (one_of)

  - (id)anyObject {
    if (0 == [self count]) return nil;
    if (1 == [self count]) return [self objectAtIndex:0];

    return [self objectAtIndex:(arcrandom() % [self count])];
  }

@end

然后,像这样使用它:

NSString *thingy = [[NSArray arrayWithObjects:@"1", @"2", @"3"] anyObject];

NB 要处理数字(和其他原生类型等),您必须将它们设为对象,即

NSInteger number = [[[NSArray arrayWithObjects:
                      [NSNumber numberWithInteger:1],
                      [NSNumber numberWithInteger:2],
                      [NSNumber numberWithInteger:3], nil] anyObject] intValue];

【讨论】:

  • 是的 - 这很麻烦,但我确实喜欢编译时警告和通过调试器控制台进行调试的能力。 (调试能力是我不使用宏的原因)。
猜你喜欢
  • 2010-11-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-12-31
  • 2017-02-15
  • 2019-01-21
相关资源
最近更新 更多