【问题标题】:How to go from CMutablePointer<CGFloat> to CGFloat[] in Swift如何在 Swift 中从 CMutablePointer<CGFloat> 到 CGFloat[]
【发布时间】:2014-10-05 13:42:58
【问题描述】:

我正在尝试将使用 Facebook's pop library 的 ObjC 类转换为 Swift。 Pop 使用了相当多的 C。

在 ObjC 中,我有一个看起来像这样的块...

prop.readBlock = ^(SHVGraphViewObjc *graphView, CGFloat values[]) {
                values[0] = [graphView.centerOffsets[idx] doubleValue];
            };

在 Swift 中等效的闭包定义是

prop.readBlock = {(graphView: AnyObject!, values: CMutablePointer&lt;CGFloat&gt;) in }

我不知道如何将values[0] = [graphView.centerOffsets[idx] doubleValue]; 转换为 Swift?如何让 Swift 知道 CMutablePointer&lt;CGFloat&gt; 应该是 CGFloat[]

【问题讨论】:

    标签: swift


    【解决方案1】:

    编辑:只是想在从online documentation (PDF) 了解更多信息后澄清一些事情。

    在 Swift 中有一些常用的指针类型,下面是它们映射到 C 等价物的方式:

    作为参数的指针

    CConstVoidPointer     => const void *
    CMutableVoidPointer   => void *
    CConstPointer<Type>   => const Type * 
    CMutablePointer<Type> => Type *
    

    作为返回类型、变量和参数的指针*

    COpaquePointer      => void *
    UnsafePointer<Type> => Type *
    

    注意:参数在超过一个指针级别时遵循此规则,否则请参见上文。

    类类型指针

    CConstPointer<Type>              => Type * const *
    CMutablePointer<Type>            => Type * __strong *
    AutoreleasingUnsafePointer<Type> => Type **
    

    Swift 指针

    在 Swift 中使用 CConstPointer&lt;Type&gt; 指针时,您可以传递以下任何一种:

    • nil,将被评估为 NULL 指针
    • CConstPointer&lt;Type&gt;
    • CConstVoidPointer
    • CMutablePointer&lt;Type&gt;
    • 一个CMutableVoidPointer
    • AutoreleasingUnsafePointer&lt;Type&gt; 值,必要时将转换为 CConstPointer&lt;Type&gt;
    • 通过地址传递的Type 值(&amp; 运算符)
    • Type[] 数组

    注意:CConstVoidPointer 也可以采用上述任何值。

    在 Swift 中使用 CMutablePointer&lt;Type&gt; 指针时,您可以传递以下任何一种:

    • nil,将被评估为 NULL 指针
    • CMutablePointer&lt;Type&gt;
    • 通过地址传递的Type 值(&amp; 运算符)
    • 通过地址传递的Type[] 数组(&amp; 运算符)

    注意:CMutableVoidPointer 可以采用除 CMUtableVoidPointer 值之外的任何上述值。

    因此,在您的情况下,CMutablePointer&lt;CGFloat&gt; 也可能是指向 CGFloat 值数组的指针。虽然我不完全确定如何在 Swift 中取消引用它。 (也许是as 运算符?)

    【讨论】:

    • 在这种情况下,我不是在调用块。 Facebook 的流行音乐库称之为。我需要知道的是如何使用values 作为GCFloats 的数组,来自inside 块。
    • 我会说CGFloat[] 就足够了,我确信 Swift 会将任何指针编组为数组(与 C 库互操作时类似于 C#)。
    • 如果我将输入块从CMutablePointer&lt;CGFloat&gt; 更改为CGFloat[],它会显示CMutablePointer&lt;CGFloat&gt; is not a subtype of CGFloat[]
    • 也许保持您的CMutablePointer&lt;CGFloat&gt; 不变。您可以使用Array&lt;CGFloat&gt;.convertFromHeapArray(...) 并从CMutablePointer 传递RawPointerowner 属性。不过,这对我来说有点摸不着头脑。
    • 我在这里找到了解决方案 (twitter.com/BigZaphod/status/475137485602045952),但看起来您的最新编辑也涵盖了它。我最终做的是let data = UnsafePointer&lt;CGFloat&gt;(values) data[0] = CGFloat(graphView.centerOffsets[index])。谢谢!
    【解决方案2】:

    虽然 SiLo 的回答非常详细,但这里的具体问题由 Ross 的 cmets 在其下方回答,所以我想我会将这些扩展为完整的答案。

    我最近需要这样做,以便通过 Swift 与我的 GPUImage 框架交互。对于我的 Harris 角点检测器,我在每个处理过的帧上使用了一个回调块,它提供了一个 C 数组,其中包含 X、Y 坐标对中的 OpenGL 浮点值,以及该数组的大小。我使用 C 数组来提高性能,因为这将在实时视频中每秒提供 30-60 次。在 Objective-C 中,我会使用如下代码进行设置:

    UIImage *sourceImage = [UIImage imageNamed:@"ChairTest.png"];
    
    GPUImageHarrisCornerDetector *cornerDetector = [[GPUImageHarrisCornerDetectionFilter alloc] init];
    
    [cornerDetector setCornersDetectedBlock:^(GLfloat* cornerArray, NSUInteger cornersDetected, CMTime frameTime) {
        NSLog(@"Number of corners detected: %d", cornersDetected);
        NSLog(@"Corner 1, X: %f, Y: %f", cornerArray[0], cornerArray[1]);
    }];
    
    GPUImagePicture *inputPicture = [[GPUImagePicture alloc] initWithImage:sourceImage];
    [inputPicture addTarget:cornerDetector];
    [inputPicture processImage];
    

    在我破译了正确的闭包语法之后,我无法完全弄清楚如何访问输入 C 数组的值,我将角坐标交给处理块。 Sean Heber's tweet about this 指出了一种方法,我用它把上面的 Objective-C 翻译成下面的 Swift 代码:

    let sourceImage = UIImage(named: "ChairTest.png")
    
    let cornerDetector = GPUImageHarrisCornerDetectionFilter()
    
    cornerDetector.cornersDetectedBlock = { (cornerArray:CMutablePointer<GLfloat>, cornersDetected:Int, frameTime:CMTime) in
        println("Number of corners detected: \(cornersDetected)")
        let corners = UnsafePointer<GLfloat>(cornerArray)
        println("Corner 1, X: \(corners[0]) Y: \(corners[1])")
    }
    
    let inputPicture = GPUImagePicture(image: sourceImage)
    inputPicture.addTarget(cornerDetector)
    inputPicture.processImage()
    

    这似乎在功能上是相同的。使用.withUnsafePointer() 可能更安全,但我还没有完全掌握它的语法。

    【讨论】:

      猜你喜欢
      • 2014-10-10
      • 1970-01-01
      • 2017-04-26
      • 1970-01-01
      • 2018-10-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-08-27
      相关资源
      最近更新 更多