如何在Swift中从CMutablePointer<CGFloat>转换为CGFloat[]?

11

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

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

prop.readBlock = ^(SHVGraphViewObjc *graphView, CGFloat values[]) {
                values[0] = [graphView.centerOffsets[idx] doubleValue];
            };
在Swift中等效的闭包定义如下: prop.readBlock = {(graphView: AnyObject!, values: UnsafeMutablePointer<CGFloat>) in } 我无法确定如何将 values[0] = [graphView.centerOffsets[idx] doubleValue]; 转换为Swift?我该如何让Swift知道 UnsafeMutablePointer<CGFloat> 应该是一个 CGFloat[]
2个回答

9

编辑:在阅读在线文档(PDF)后,我想澄清一些事情。

在Swift中有几种常用的指针类型,以下是它们与C等效类型的映射:

指针作为参数

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

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

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

注意:以下规则仅适用于指针层数大于1的参数,否则请参见上文。

类类型的指针

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

Swift指针

当在Swift中使用CConstPointer<Type>指针时,您可以传递以下任何一种:

  • nil,将被评估为NULL指针
  • CConstPointer<Type>
  • CConstVoidPointer
  • CMutablePointer<Type>
  • CMutableVoidPointer
  • AutoreleasingUnsafePointer<Type>值,如果需要会被转换为CConstPointer<Type>
  • 通过地址传递的Type值(使用&运算符)
  • 通过地址传递的Type[]数组

注意:CConstVoidPointer也可以接受以上任何一个值。

当在Swift中使用CMutablePointer<Type>指针时,您可以传递以下任何一种:

  • nil,将被评估为NULL指针
  • CMutablePointer<Type>
  • 通过地址传递的Type值(使用&运算符)
  • 通过地址传递的Type[]数组(使用&运算符)

注意:CMutableVoidPointer除了可以接受以上任何一个值之外,还可以接受CMUtableVoidPointer值。

因此,在您的情况下,CMutablePointer<CGFloat>也可能是指向CGFloat值数组的指针。虽然我不完全确定如何在Swift中对其进行解引用。(也许使用as运算符?)


在这种情况下,我不会调用该块。Facebook的pop库会调用它。我需要知道的是如何从内部使用values作为GCFloats数组。 - Ross Kimes
我认为 CGFloat[] 应该足够了,我相信 Swift 会将任何指针转换为数组(类似于 C# 在与 C 库进行交互时的方式)。 - Erik
1
如果我将输入块从CMutablePointer<CGFloat>更改为CGFloat[],它会显示CMutablePointer<CGFloat>不是CGFloat[]的子类型。 - Ross Kimes
д№ҹи®ёдҝқз•ҷжӮЁзҡ„CMutablePointer<CGFloat>дёҚеҸҳгҖӮжӮЁеҸҜд»ҘдҪҝз”ЁArray<CGFloat>.convertFromHeapArray(...)пјҢ并传е…ҘжқҘиҮӘCMutablePointerзҡ„RawPointerе’ҢownerеұһжҖ§гҖӮиҷҪ然еҜ№жҲ‘жқҘиҜҙиҝҷиҝҳжҳҜжңүдәӣеҶ’йҷ©гҖӮ - Erik
我在这里找到了解决方案 (https://twitter.com/BigZaphod/status/475137485602045952),但看起来你最近的编辑也已经涵盖了它。我最后做的是 let data = UnsafePointer<CGFloat>(values) data[0] = CGFloat(graphView.centerOffsets[index])。谢谢! - Ross Kimes
请将您的解决方案添加到单独的答案中,并将其标记为正确答案。谢谢。 - aleclarson

3
尽管SiLo的回答非常详细,但是这里的特定问题被Ross在其下面的评论中回答了,因此我想扩展这个答案。

我最近需要这样做是为了通过Swift与我的GPUImage框架进行接口。对于我的Harris角点检测器,我在每个处理过的帧上使用回调块,该块提供了一个OpenGL浮点值的C数组,其中包含X、Y坐标对,以及该数组的大小(以对为单位)。由于这将在实时视频上每秒提供30-60次,我使用C数组来提高性能。在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关于这个问题的推文 指出了一种做法,我用它将上面的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()可能更安全,但我还没有掌握它的语法。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接