【问题标题】:Passing arrays of CGFloats to a method将 CGFloats 数组传递给方法
【发布时间】:2014-01-03 22:35:47
【问题描述】:

我仍然对 Obj C 中的基本数据类型有所了解,所以这个确实在考验我。我已经查看了十几个或更多相关问题,但仍然无法弄清楚。

我在 UIView 子类中有现有的硬编码(基于我在某处找到的示例代码):

CGColorSpaceRef colourSpace = CGColorSpaceCreateDeviceRGB();
CGFloat gradientColours[16] = {
    0.0f, 0.8f, 0.0f, 1.0f, // green
    1.0f, 1.0f, 0.0f, 1.0f, // yellow
    0.9f, 0.0f, 0.0f, 1.0f  // red
};
CGFloat gradientLocations[] = { 0.0, 0.5, 1.0 };
CGGradientRef gradient = CGGradientCreateWithColorComponents(colourSpace, gradientColours, gradientLocations, 3);

这很好,但每个实例都会使用相同的渐变,所以我想添加一个方法来设置渐变。

我希望能够像这样打一个简单的电话

[myView1 setGradient:{
    0.0f, 0.8f, 0.0f, 1.0f, // green
    1.0f, 1.0f, 0.0f, 1.0f, // yellow
    0.9f, 0.0f, 0.0f, 1.0f  // red
    withLocations:{ 0.0, 0.5, 1.0 }];

我终其一生都无法弄清楚如何编写方法签名来接受这两个数组,以使它们可以在CGGradientCreateWithColorComponents 构造函数中成功使用。

非常感谢任何帮助。

【问题讨论】:

标签: ios variables methods


【解决方案1】:
 - (void) setGradient:(CGFloat*)gradientArray withArrayLength:(int)lengthOfArray {
      // do stuff here
 }

然后你可以像这样调用方法:

 CGFloat someArray[16] = { ... };
 [someObject setGradient:someArray withArrayLength:16];

编辑:Rob 提醒我在这种情况下需要一个包含数组长度的参数。

【讨论】:

    【解决方案2】:

    您可以使用NSArray 和NSNumber 文字语法来获得类似的东西。你可以这样称呼它:

    [self setGradientColorComponents:@[
        @0.0f, @0.8f, @0.0f, @1.0f, // green
        @1.0f, @1.0f, @0.0f, @1.0f, // yellow
        @0.9f, @0.0f, @0.0f, @1.0f  // red
    ] withLocations:@[
        @0.0f, @0.5f, @1.0f
    ]];
    

    这是你如何实现它的:

    - (void)setGradientColorComponents:(NSArray *)components withLocations:(NSArray *)locations {
        NSUInteger count = components.count;
        CGFloat componentFloats[count];
        for (NSUInteger i = 0; i < count; ++i) {
            componentFloats[i] = [components[i] floatValue];
        }
    
        count = locations.count;
        CGFloat locationFloats[count];
        for (NSUInteger i = 0; i < count; ++i) {
            locationFloats[i] = [locations[i] floatValue];
        }
    
        CGColorSpaceRef rgb = CGColorSpaceCreateDeviceRGB();
        CGGradientRef gradient = CGGradientCreateWithColorComponents(rgb, componentFloats, locationFloats, count);
        CGColorSpaceRelease(rgb);
    
        // do whatever with gradient
    
        CGGradientRelease(gradient);
    }
    

    另一方面,您可以使用可变参数函数。由于可变参数函数只能有一个可变参数列表,因此您必须将位置与颜色分量混合。您还必须以某种方式标记列表的末尾。你可以这样称呼它:

    [self setGradient:
        0.0, 0.0, 0.8, 0.0, 1.0, // location 0.0, color green
        0.5, 1.0, 1.0, 0.0, 1.0, // location 0.5, color yellow
        1.0, 0.9, 0.0, 0.0, 1.0, // location 1.0, color red
        -1.0
    ];
    

    这更危险,因为您需要确保只将双精度值传递给函数,并且需要确保您通过列表末尾的 -1.0 标记。我建议坚持我的第一个解决方案(使用 NSArray 和 NSNumber 文字)。也就是说,这是实现可变参数解决方案的方式:

    - (void)setGradient:(CGFloat)location0, ... {
        size_t count = 0;
        va_list ap;
        va_start(ap, location0);
        // Note that when you pass a float as a variadic argument, the compiler promotes it to double.
        double f = location0;
        while (f >= 0.0 && f <= 1.0) {
            ++count;
            f = va_arg(ap, double);
        }
        va_end(ap);
        NSAssert(count % 5 == 0, @"number of arguments is %lu which is not a multiple of 5", (unsigned long)count);
    
        count /= 5;
        CGFloat locations[count];
        CGFloat components[4 * count];
        va_start(ap, location0);
        f = location0;
        for (size_t i = 0; i < count; ++i) {
            locations[i] = (CGFloat)f; f = va_arg(ap, double);
            components[i * 4 + 0] = (CGFloat)f; f = va_arg(ap, double);
            components[i * 4 + 1] = (CGFloat)f; f = va_arg(ap, double);
            components[i * 4 + 2] = (CGFloat)f; f = va_arg(ap, double);
            components[i * 4 + 3] = (CGFloat)f; f = va_arg(ap, double);
        }
        va_end(ap);
    
        CGColorSpaceRef rgb = CGColorSpaceCreateDeviceRGB();
        CGGradientRef gradient = CGGradientCreateWithColorComponents(rgb, components, locations, count);
        CGColorSpaceRelease(rgb);
    
        // do whatever with gradient
    
        CGGradientRelease(gradient);
    }
    

    【讨论】:

    • 这两个看起来都过于复杂了。在第一个解决方案中,参数被包裹在一个 NSArray 中,但是 CGGradientCreateWithColorComponents() 函数需要一个 CGFloats 数组。为什么不简单地将 CGFloats 数组作为参数传递?
    • 如果有更直接的方法,我很想看看怎么做。与此同时,这个对我有用。正如我在问题中所说,我还不熟悉该语言的基础知识。十天前我开始使用 Obj C 编写,之前没有任何 C 类型语言的经验!
    • @DavidSchwartz 您不能将本机数组作为 C 中的参数传递。您可以将指针传递给数组的第一个元素,但是您还必须以某种方式传递数组的长度或添加最后一个哨兵。无论哪种方式都容易出错,因为编译器无法帮助您检测错误计数或丢失的标记,并且任何一种错误都可能导致未定义的行为。这就是为什么我建议在我的第一个解决方案中使用 Objective-C 文字。在该解决方案中,任何可能的错误要么在编译时被捕获,要么在运行时检测到并导致异常。
    • @robmayoff 感谢您的解释。我显然需要复习我的 C 基础知识...
    猜你喜欢
    • 2010-10-23
    • 2012-11-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-06-23
    • 2019-03-22
    • 2012-01-20
    • 2017-04-28
    相关资源
    最近更新 更多