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[]
?
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:
CConstVoidPointer => const void *
CMutableVoidPointer => void *
CConstPointer<Type> => const Type *
CMutablePointer<Type> => Type *
COpaquePointer => void *
UnsafePointer<Type> => Type *
NOTE: Arguments follow this rule only when they are more than one pointer level deep, otherwise see above.
CConstPointer<Type> => Type * const *
CMutablePointer<Type> => Type * __strong *
AutoreleasingUnsafePointer<Type> => Type **
When using the CConstPointer<Type>
pointer in Swift, you may pass any one of these:
nil
, which will be evaluated as a NULL
pointerCConstPointer<Type>
valueCConstVoidPointer
valueCMutablePointer<Type>
valueCMutableVoidPointer
AutoreleasingUnsafePointer<Type>
value which will be converted to CConstPointer<Type>
if necessaryType
value passed by address (&
operator)Type[]
arrayNOTE: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
pointerCMutablePointer<Type>
valueType
value passed by address (&
operator)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?)
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With