How to implement C-Style callback functions using swift? - objective-c

I found an example for IOKit:
var notification:io_object_t
let matching:NSDictionary = IOServiceNameMatching("IODisplayWrangler").takeRetainedValue()
let displayWrangler = IOServiceGetMatchingService(kIOMasterPortDefault, matching)
let notificationPort = IONotificationPortCreate(kIOMasterPortDefault)
IOServiceAddInterestNotification(notificationPort, displayWrangler, kIOGeneralInterest, displayPowerNotificationsCallback, nil, &notification)
CFRunLoopAddSource (CFRunLoopGetCurrent(), IONotificationPortGetRunLoopSource(notificationPort), kCFRunLoopDefaultMode);
IOObjectRelease (displayWrangler);
The above example is clear to me - so far. But IOServiceAddInteresNotification wants a callback function. In it's simple to do this, by implementing the C-Style function somewhere in the .m-file.
The documentation says that I have to use a callback of type IOServiceInterestCallback.
In C-Style it is defined as follows:
typedef void ( *IOServiceInterestCallback)( void *refcon, io_service_t service, uint32_t messageType, void *messageArgument );
And on objC everything seems to work out perfectly.
What is the equivalent solution in swift? How do I declare the callback function without creating a C or objC file for this?
Any ideas?
Cheers,
Jack

You cannot create C function like callbacks in Swift as closures are not compatible with CFunctionPointer. You can implement some workaround in Objective-C or C. Example is describe in Objective-C Wrapper for CFunctionPointer to a Swift Closure

Related

Using a reference to CFPropertyListRef in Swift

I'm currently converting some Objective-C code to swift and I am stuck.
I do have an internal API which fills a CFPropertyList and give back it's format.
MyFunction(CFPropertyListRef list, CFPropertyListFormat *fmt);
In Objective-C I'm calling it via
CFDictionaryRef myList;
CFPropertyListFormat fmt;
MyFunction(&myList, &fmt)
Via the "Generated Interface" i can see that swift converted to
MyFunction(_ list: CFPropertyList!, _ fmt: UnsafeMutablePointer<CFPropertyListFormat>))
When I'm trying to call the function in swift via
var fmt = CFPropertyListFormat.XMLFormat_v1_0
var plist = NSDictionary() as CFPropertyListRef
MyFunction(plist, &fmt)
I'm getting a EXC_BAD_ACCESS.
As the compiler doesn't complain about the types I think this should be right.
Any help is very appreciated!
Thanks
If your usage in Objective-C is really right, the function header of your MyFunction needs to be something like this:
extern void MyFunction(CFPropertyListRef *list, CFPropertyListFormat *fmt);
(CFPropertyListRef actually is just a typealias of void * in Objective-C/C. So, the compiler rarely outputs warnings for many possible type mis-uses.)
And Swift 2 imports such function as:
public func MyFunction(list: UnsafeMutablePointer<Unmanaged<CFPropertyList>?>, _ fmt: UnsafeMutablePointer<CFPropertyListFormat>)
So, assuming you have changed the function header as above,
you need to use it as follows:
var fmt: CFPropertyListFormat = .XMLFormat_v1_0
var umPlist: Unmanaged<CFPropertyList>? = nil
MyFunction(&umPlist, &fmt)
var plist = umPlist?.takeRetainedValue() //or this may be `umPlist?.takeUnretainedValue()`

How to get Objective-C block input parameter in Swift Closure

I need use a Objective-C SDK in my Swift project, the Objc demo is in below
[[AlipaySDK defaultService] payOrder:orderString fromScheme:appScheme callback:^(NSDictionary *resultDic) {
NSLog(#"reslut = %#",resultDic);
}];
It pass a block to payOrder:orderString:: function, but when I call it in Swift, the auto complete help me generate these code
AlipaySDK.defaultService().payOrder(orderString, fromScheme: self.aliAppScheme, callback: { ([NSObject : AnyObject]!) -> Void in
println("Pay Success")
})
in Swift the closure input parameter has no name, in Objc it named resultDict, but in Swift I don't know how to get it pointer, Please help me, Thanks
In the objective C block, it takes an NSDictionary parameter. With Swift closures, the closure is already typed so you don't have to declare NSDictionary as the type and you really don't even need -> Void. Also the , callback: is extraneous in Swift as well because of trailing closures so your final product should be:
AlipaySDK.defaultService().payOrder(orderString, fromScheme: self.aliAppScheme) { resultDict in
println("Pay Success")
}

Using Swift CFunctionPointer to pass a callback to CoreMIDI API

It may be that this is actually not possible currently, which would be unfortunate. I'm trying to call the CoreMIDI API to set up a MIDI input. This is what I'm trying to do in Swift:
var midiClient = MIDIClientRef()
var inputPort = MIDIEndpointRef()
var status: OSStatus
func readProc(packetList: UnsafePointer<MIDIPacketList>, readProcRefCon: UnsafeMutablePointer<Void>, srcConnRefCon: UnsafeMutablePointer<Void>) -> Void {
}
status = MIDIClientCreate("MIDI client", nil, nil, &midiClient);
status = MIDIDestinationCreate(midiClient, "MIDI input", readProc, nil, &inputPort);
But I get this error: '(UnsafePointer, UnsafeMutablePointer, UnsafeMutablePointer) -> Void' is not convertible to 'MIDIReadProc'
MIDIReadProc's typedef is the following:
typealias MIDIReadProc = CFunctionPointer<((UnsafePointer<MIDIPacketList>, UnsafeMutablePointer<Void>, UnsafeMutablePointer<Void>) -> Void)>
Is there a way to get a function pointer for my readProc method to pass to the MIDIDestinationCreate API?
In Swift 2.0 (as part of Xcode 7), C APIs that deal in function pointers use function types that are annotated #convention(c). You can pass any Swift function, method, or closure as a #convention(c) function type — but only if that closure conforms to C conventions... e.g. it can't capture state from its surrounding scope.
For details, see Type Attributes in The Swift Programming Language.
As for what's in Xcode 6: Swift 1.x doesn't have a way to convert a Swift function or closure to a C function pointer -- the sole use of the CFunctionPointer type is to pass function pointers imported from (Obj)C APIs to other (Obj)C APIs.
You can declare a function pointer in C code that you expose to Swift via your project's bridging header, then use Swift to pass that to CoreMIDI. But since you're going to be reaching across a bridge anyway, you might instead think about which parts of your project are best to keep in C and what the best interface is from those parts to your Swift code is.
Swift 1.x (Old Way)
There's a way to do that - Objective-C Runtime is the trick.
import CoreMIDI
let block : #objc_block
(UnsafePointer<MIDIPacketList>,
UnsafeMutablePointer<Void>,
UnsafeMutablePointer<Void>) -> Void =
{ (pktlist,readProcRefCon,srcConnRefCon) in
//Your code goes here...
}
let imp : COpaquePointer =
imp_implementationWithBlock(unsafeBitCast(block, AnyObject.self))
let callback : MIDIReadProc = unsafeBitCast(imp, MIDIReadProc.self)
Works with CoreFoundation callbacks.
Should work for CoreMIDI too.
Swift 2.x (New Way)
In Swift 2 the process becomes "less hacky" (and slightly more readable).
import CoreMIDI
let callback : #convention(c) (pktlist : UnsafePointer<MIDIPacketList>,
readProcRefCon : UnsafeMutablePointer<Void>,
srcConnRefCon : UnsafeMutablePointer<Void>) -> Void =
{ (pktlist, readProcRefCon, srcConRefCon) in
}
let usableCallback = unsafeBitCast(callback, MIDIReadProc.self)

Swift : Define a closure compatible with Objective-C block

I tried to declare a closure matching the following Objective-C block:
typedef void(^TyphoonDefinitionBlock)(TyphoonDefinition *definition);
like this:
var config: TyphoonDefinitionBlock = { (definition: TyphoonDefinition) in
definition.injectProperty("quest", with: nil)
}
. . . and got the following error. (see image).
What's the correct way to do this?
You need to declare definition as an ImplicitlyUnwrappedOptional (TyphoonDefinition!) because in objective-C it is a pointer that can be nil.
Normal variables (and constants) in swift cannot be nil. They must contain a value.
I'm using typealias, taken from http://berzniz.com/post/87924122326/notes-from-coding-in-swift
typealias resultBlock = (success: Bool, result: AnyObject!) -> Void
Like to explain it in details,start with your piece of code
Objective C
typedef void(^TyphoonDefinitionBlock)(TyphoonDefinition *definition);
In Swift you make it like this
typealias TyphoonDefinitionBlock = (definition:TyphoonDefinition?)->Void
If you want to intimate to caller object after particular moment you need to make a property.
var typhoonDefinitionCompletion:BlockTyphoonDefinitionBlock?
you can use typhoonDefinitionCompletionand you can raise the callback message like this.
self.typhoonDefinitionCompletion!(definition:passyourtyphoneDefinition)

Objective C glutDisplayFunc with method

How can you use a Objective C method as an argument for glutDisplayFunc (and functions like it)? I'm quite new to ObjC, so I don't completely know how this works
In C++, you can just pass in a void, but in ObjC, I tried this:
//...
glutDisplayFunc([self display]);
//...
-(void) display{
glutPostRedisplay();
}
I've also tried static methods
//...
glutDisplayFunc([self display]);
//...
+(void) display{
glutPostRedisplay();
}
but every time I get the error "passing 'void' to parameter with incompatible type void(*)(void)".
I thought you could just pass in a void.
So, how can I make this work (it has to be a method)
In C++, you can just pass in a void
No, you can't.
So, how can I make this work (it has to be a method)
You can't. What you're interested in would be as something known as closure or delegate, but GLUT will just take global scope C style callback functions. The best thing you could to was write a global scope wrapper with a calling convention compatible to C, which then calls the method of a global scope class instance.