Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to go from CMutablePointer<CGFloat> to CGFloat[] in Swift

Tags:

swift

I am trying to convert an ObjC class that uses Facebook's pop library to Swift. Pop uses quite a bit of C.

In ObjC, I have a block that looks like this...

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

The equivalent closure definition in Swift would be

prop.readBlock = {(graphView: AnyObject!, values: CMutablePointer<CGFloat>) in }

What I can't figure out is how to convert the values[0] = [graphView.centerOffsets[idx] doubleValue]; to Swift? How do I let Swift know that CMutablePointer<CGFloat> should be a CGFloat[]?

like image 933
Ross Kimes Avatar asked Jun 05 '14 03:06

Ross Kimes


2 Answers

EDIT: Just wanted to clarify a few things after learning a bit more from the online documentation (PDF).

There are a few commonly used pointer types in Swift, here is how they map to C equivalents:

Pointers as Arguments

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

Pointers as Return Types, Variables, and Arguments*

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

NOTE: Arguments follow this rule only when they are more than one pointer level deep, otherwise see above.

Pointers for Class Types

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

Swift Pointers

When using the CConstPointer<Type> pointer in Swift, you may pass any one of these:

  • nil, which will be evaluated as a NULL pointer
  • A CConstPointer<Type> value
  • A CConstVoidPointer value
  • A CMutablePointer<Type> value
  • A CMutableVoidPointer
  • A AutoreleasingUnsafePointer<Type> value which will be converted to CConstPointer<Type> if necessary
  • A Type value passed by address (& operator)
  • A Type[] array

NOTE:CConstVoidPointer can take any of the above values as well.

When using the CMutablePointer<Type> pointer in Swift, you may pass any one of these:

  • nil, which will be evaluated as a NULL pointer
  • A CMutablePointer<Type> value
  • A Type value passed by address (& operator)
  • A Type[] array passed by address (& operator)

NOTE:CMutableVoidPointer can take any of the above in addition to CMUtableVoidPointer values.

So it would seem in your case that a CMutablePointer<CGFloat> could also be a pointer to an array of CGFloat values. Though I am not completely sure how to dereference that in Swift. (Perhaps the as operator?)

like image 59
Erik Avatar answered Nov 01 '22 03:11

Erik


While SiLo's answer is extremely detailed, the specific question here is answered by Ross' comments underneath it, so I thought I'd expand those into a full answer.

I needed to do this recently in order to interface with my GPUImage framework via Swift. For my Harris corner detector, I use a callback block on each processed frame that provides a C array of OpenGL floating-point values in X, Y coordinate pairs, along with the size of that array in pairs. I use a C array for performance, since this will be provided 30-60 times per second on live video. In Objective-C, I would set this up using code like the following:

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];

After I deciphered the proper closure syntax, I couldn't quite figure out how to access the values of the input C array where I hand over corner coordinates to the processing block. Sean Heber's tweet about this points out one way to do this, which I used to translate the above Objective-C to the following Swift code:

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()

This appears to be functionally identical. It might be safer to use .withUnsafePointer(), but I haven't quite gotten the syntax on that down.

like image 23
Brad Larson Avatar answered Nov 01 '22 03:11

Brad Larson