I've read several of the previous discussion about the subject but since I'm relatively new to Objective-C, I don't really understand them. (Blocks, selectors, and delegate are very new to me).
Here is the situation:
I'm using those abstract class RtMidi that are written in c++
void MidiInApi :: setCallback( RtMidiIn::RtMidiCallback callback, void *userData )
{
if ( inputData_.usingCallback ) {
errorString_ = "MidiInApi::setCallback: a callback function is already set!";
RtMidi::error( RtError::WARNING, errorString_ );
return;
}
if ( !callback ) {
errorString_ = "RtMidiIn::setCallback: callback function value is invalid!";
RtMidi::error( RtError::WARNING, errorString_ );
return;
}
inputData_.userCallback = (void *) callback;
inputData_.userData = userData;
inputData_.usingCallback = true;
}
I also have a class that Reciever that implements that callback (rtMidiCallback).
And at some point in my main file I need to write something like this
midiIn->setCallback(rtMidiCallback);
This Would be in a c++ context but in Objective-C I have no idea how to do it.
If you have any ideas, pointers I would be glad to discuss about it with you. Thank you very much
Best,
greg.
It's possible to have C++ and Objective-C within the same project and even within the same file (Objective-C++ with file extension .mm). If the code you're using is designed for a C++ callback, it may be easier to provide that and communicate between different object types outside of that mechanism.
// CPPClass.h
#ifndef CPPClass_h
#define CPPClass_h
class CPPClass {
private:
id m_ocObject;
public:
CPPClass(id ocObject);
virtual ~CPPClass();
void verifyCPP();
};
#endif
// OCClass.h
#import <Foundation/Foundation.h>
class CPPClass;
#interface OCClass : NSObject {
CPPClass *cppObject;
}
- (void)ocCallback;
- (void)verifyOC;
#end
// OCClass.mm
#import "OCClass.h"
#import "CPPClass.h"
#include <iostream>
#implementation OCClass
- (id)init {
self = [super init];
if (self) {
cppObject = new CPPClass(self);
}
return self;
}
- (void)dealloc {
delete cppObject;
}
- (void)ocCallback {
NSLog(#"Objective-C called from C++");
}
- (void)verifyOC {
NSLog(#"Objective-C called from Objective-C");
cppObject->verifyCPP();
}
#end
CPPClass::CPPClass(id ocObject) : m_ocObject(ocObject)
{}
CPPClass::~CPPClass() {}
void CPPClass::verifyCPP() {
std::cout << "C++ called from Objective-C" << std::endl;
[m_ocObject ocCallback];
}
To activate this, some other .mm file would have:
#import "OCClass.h"
...
OCClass *test = [[OCClass alloc] init];
[test verifyOC];
Related
I have a mixed-language project, Objective C and Swift, in XCode 6.
Singleton.h
#import <Foundation/Foundation.h>
enum {
enum_A = 0,
enum_B,
enum_C,
enum_D,
enum_E,
enum_F,
enum_G,
} enums;
#interface Singleton : NSObject
+ (id)sharedSingleton;
#end
Singleton.m
// Nothing's special in this file
#import "Singleton.h"
static Singleton *shared = nil;
#implementation Singleton
- (id)init {
self = [super init];
if (self) {
}
return self;
}
#pragma mark - Interface
+ (Singleton *)sharedSingleton {
static dispatch_once_t pred;
dispatch_once(&pred, ^{
shared = [[Singleton alloc] init];
});
return shared;
}
#end
ViewController.swift
import UIKit
class ViewController: UIViewController {
let singleton = Singleton.sharedSingleton() as Singleton
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
let n = NSNumber(char: enum_E) // ERROR HERE!!!
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
(Of course I had to setup bridging header file, having #import "Singleton.h" added).
The ERROR is:
Cannot invoke 'init' with an argument list of type '(char: Int)'
It's strange that Swift can still recognize enum_E (I see it colorized in blue) but still pops up this error.
I tried (char)enum_E but still no luck.
Do you have any ideas?
Thanks,
Okay, apparently there actually is a difference between enums created in Objective-C and Swift. I assumed there was no difference, thus I only tested my approach in a Swift Playground.
enum created in Swift
// UInt32 used to have the same underlying type in both examples
enum TestEnum : UInt32 {
case A, B, C
}
var x = NSNumber(unsignedInt: TestEnum.C.rawValue)
// x == 2
To get the raw value from an enum value in Swift, you have to explicitly transform the enum value into the raw value. This can be done by adding .rawValue to your enum value.
enum created in Objective-C
Objective-C
enum TestEnum {
A = 0,
B = 1,
C = 2
};
Swift
let x : TestEnum = C
var number = NSNumber(unsignedInt: C.value) // alternative: x.value
println("the number is \(number)")
// Outputs: the number is 2
The difference to the Swift enums seems to be that you have to use .value instead of .rawValue and you can not prefix them with the type. The raw type in this case is UInt32.
Tested in Xcode 6.1.1, iOS SDK 8.1, iOS Simulator 8.1
Consider this code example:
class SomeArbitrarilyNamedClassPlusPlus {
public:
SomeArbitrarilyNamedClassPlusPlus(NSObject *object) { object_ = object; }
SomeArbitrarilyNamedClassPlusPlus() { object_ = nil; }
private:
NSObject *object_;
};
#interface SomeArbitrarilyNamedClassObjective : NSObject
{
SomeArbitrarilyNamedClassPlusPlus *_plusPlusObject;
}
#end
#implementation SomeArbitrarilyNamedClassObjective
-(id)init
{
if ((self = [super init]))
{
_plusPlusObject = new SomeArbitrarilyNamedClassPlusPlus(self);
}
return self;
}
-(void)dealloc
{
NSLog(#"deallocated");
delete _plusPlusObject;
}
#end
int main(int argc, const char * argv[])
{
{
SomeArbitrarilyNamedClassObjective *object = [[SomeArbitrarilyNamedClassObjective alloc] init];
}
return 0;
}
The object variable never gets deallocated. You can check it with Instruments - additional retain counter increment happens inside the -(id)init call.
I would never expect that attributes in C++ classes are strong and this makes me wondering - is there a way to make c++ attributes pointing on Objective-C objects weak?
UPDATE:
There is a way to avoid this using pointers to void in C++ class instead of NSObject* and initialize C++ class in -(id)init method like that:
...
_plusPlusObject = new SomeArbitrarilyNamedClassPlusPlus((__bridge void*)self);
...
However, the question still remains - is there a way to save Objective-C types inside C++ classes but make them weak?
Well, the answer turned out to be quite straightforward - use __weak attribute in C++ class:
class SomeArbitrarilyNamedClassPlusPlus {
public:
SomeArbitrarilyNamedClassPlusPlus(NSObject* object) { object_ = object; }
SomeArbitrarilyNamedClassPlusPlus() { object_ = nil; }
private:
__weak NSObject* object_;
};
I'm doing some Interop from Mono C# to Obj-C and ran into this problem.
The C# code needs to pass a callback - which it does with a function pointer.
I can get the function pointer from the Obj-C side and call it and everything works.
But I now need to give that function pointer as a callback to third party API which works with blocks as a callback.
I want the third party to call the C# function - so in a way i'm trying to either convert the function pointer to a block so the third party can run it, or make some sort of a bridge - create my own block that runs that function pointer and give it to the third party. I can't seem to find a way to do that - how would I generate a block with info of which function to run and then give it to the third party.
Maybe there's another option for me?
Edit: Putting the function in a global variable might work but I want to be able to have a multitude of those as the third party API is asynchronous and I don't want it calling the wrong callback.
Code I tried :
typedef void (*DummyAction)(char * result);
typedef void (^DummyBlock)(char * result);
#interface FunctionToBlock : NSObject
{
DummyAction function;
DummyBlock block;
}
- (id) initWithFunction: (DummyAction) func;
- (DummyBlock) block;
#end
#implementation FunctionToBlock : NSObject
- (id) initWithFunction: (DummyAction) func {
if (self = [super init]) {
function = func;
block = ^(char * result) {
function(result);
};
}
return self;
}
- (DummyBlock) block {
return block;
}
#end
And then I run this with
void RegisterCallback( char * text, DummyAction callback)
{
FunctionToBlock *funcToBlock = [[FunctionToBlock alloc] initWithFunction : callback];
funcToBlock.block(text);
}
And it fails with BAD_ACCESS. Maybe i'm doing something wrong as i'm not very proficient with Obj-C yet. I can confirm that the callback is ok if run directly and that the block is being called but it fails on the function(result) line.
why not just have a simple function
typedef void (*DummyAction)(char * result);
typedef void (^DummyBlock)(char * result);
DummyBlock functionToBlock(DummyAction func) {
return [[^(char * result) {
func(result);
} copy] autorelease];
}
What about
void (*myFunc)(int x); // ... your function pointer
void (^myBlock)(int) = ^(int x) {
myFunc(x);
};
Then myBlock is a block that captures the value of the function pointer and calls the function when the block is executed.
ADDED: My suggestion, based on your code, using a #property (and assuming that you compile with ARC):
FunctionToBlock.h:
typedef void (*DummyAction)(char * result);
typedef void (^DummyBlock)(char * result);
#interface FunctionToBlock : NSObject
{
DummyAction function; // Not really needed.
}
- (id) initWithFunction: (DummyAction) func;
#property(copy, nonatomic) DummyBlock block; // "copy" is important here!
#end
FunctionToBlock.m:
#import "FunctionToBlock.h"
#implementation FunctionToBlock : NSObject
#synthesize block = _block; // Can be ommitted if you use Xcode 4.4 or later.
- (id) initWithFunction: (DummyAction) func
{
if (self = [super init]) {
function = func; // Not really needed.
self.block = ^(char * result) {
func(result); // Use "func", not "self->function", to avoid retain cycle.
};
}
return self;
}
A block is under the hood a pointer to a local data structure. A block becomes invalid as soon as you leave the scope where it was declared. The scope is the if-statement within init; as soon as you leave that, the block is invalid.
You are breaking coding conventions here in a bad way. First, instance variables should start with an underscore, so that everyone sees what you are doing. Better to use properties without declaring instance variables at all. And every block property should be declared as "copy". If you do that, everything is fine.
In Objective-C, it is possible to pass a class as a parameter to a method:
- (void) methodThatTakesClass:(Class)theClass;
And it is possible to pass an instance that is conforming to a protocol as a parameter:
- (void) myConformInstance:(id <MyProtocol>)theObject;
Is it possible to use the combined functionality? A method which takes a class which is conforming to a certain protocol.
Yes. The following is a valid program which will log the NSObject class.
#import <Foundation/Foundation.h>
void f(Class <NSObject> c) {
NSLog(#"%#",c);
}
int main() {
f([NSObject class]);
}
This would cause a compiler error if you tried to pass a class which doesn't conform to NSObject, such as the Object class. You can also use it for methods.
- (void)printClass:(Class <NSObject>)c;
also valid:
#interface Something: Object {
}
- (void) foo:(int(*)(void))bar;
#end
#implementation Something
- (void) foo:(int(*)(void))bar {
return (*bar)();
}
#end
int someFunc( void ) {
return 9;
}
int main ( int argc, char **argv ) {
Something *object = [[Something alloc] init];
printf( "%i\n", [object foo:&someFunc] );
[object release];
return 0;
}
I need to pass a address of the function to a function pointer.Below is the code what i'm
trying to accomplish it.I'm sure that i'm mistaking somewhere so that i'm getting a
runtime exception.How to pass the address of a function to a function pointer.Am i
missing something in this code.
RS232Msg.h
typedef RS232Msg* (*tpNewMsg)(void);
typedef struct
{
int nMessageId;
NSString* szAsciiName;
tpNewMsg pNewMessageFunc;
} stRs232Struct;
#interface RS232Msg : NSObject
{
}
#end
RS232Msg.m
#implementation RS232Msg
-(id)initWithRS232Msg:(int)uMessageId withNewMsg:(tpNewMsg)pNewMsg withAsciiName:(const char*)szAsciiName withData:(void*)pData withSize:(size_t)uDataSize
{
//stmts;
}
#end
RS232Derived.h
#interface RS232MsgRequestSession : RS232Msg{
}
+(RS232Msg*)NewMsg;
RS232Derived.m
#implementation RS232MsgRequestSession
+(id)FromMsg:(RS232Msg*)pMsg
{
pMsg = [RS232MsgRequestSession alloc];
return pMsg;
}
-(id)init
{
if (self = [super initWithRS232Msg:[RS232MsgRequestSession getID] withNewMsg:[RS232MsgRequestSession NewMsg] withAsciiName:NULL withData:&st withSize:sizeof(st)]) {
}
return self;
}
#end
A run time exception happens when i tried to pass the address of the function
withNewMsg:
[RS232MsgRequestSession NewMsg]
to the function pointer pNewMsg() in the initWithRS232Msg
method.
[RS232MsgRequestSession NewMsg] doesn't get you the address of the method. The expression is evaluated and the result object is passed as the argument. While there is a way to access the implementation of a method directly (read this for details), there might be an easier way to achieve what you want.
Selector based approach
Instead of what you're doing right now, you can consider doing something like this,
- (id) initWithTarget:(id)aTarget action:(SEL)aSelector ... {
// save these two for later reference.
}
and later,
if ( [target respondsToSelector:theSelector] ) {
result = [target performSelector:theSelector];
}
This way you can achieve what you want.
Blocks based approach
Truth be told, Blocks are turning out to be the best addition to Objective-C.
Change the typedef to typedef RS232Msg* (^tpNewMsg)(void);
Now the init method would become,
-(id)init
{
self = [super initWithR232Msg:[RS232MsgRequestSession getID]
withNewMsg:^{
return [RS232MsgRequestSession NewMsg];
}
withAsciiName:NULL
withData:&st
withSize:sizeof(st)]
if ( self ) {
// do stuff
}
return self;
}
#end