I have a callback function in C which looks like this:
void cfunc(char* labelUpdateText)
This callback function is supposed to update the text of a label in my app's UI by changing the label's current text to whatever labelUpdateText is.
So in cfunc I'm trying to call this Objective C function:
-(void)updateLabel:(char*) text
{
[_labelProp setStringValue:[NSString stringWithFormat:#"%#", [NSString stringWithUTF8String:text]]];
}
However, I can't call the objective C function from my C function.
I tried like this:
updateLabel:labelUpdateText
But when I build the code, I get the warning 'Expression result unused'
And the 'updateLabel:labelUpdateText' doesn't execute.
What am I doing wrong?
PS: I am new to Objective C!
You need to provide the callback function with a pointer to the view containing the label and some means of updating it. All callback functions should have a context pointer of some sort which can hold information allowing them to perform context-specific actions. If you cannot change the callback function semantics then you are stuck I'm afraid, however if you can, do it something like this:
void cfunc(const char *labelUpdateText, void *contextInfo) {
YourView *view = (YourView *)contextInfo;
[view updateLabelWithText:[NSString stringWithUTF8String:labelUpdateText]];
}
You will need to provide the updateLabelWithText method in YourView and if you are using ARC there will be some bridging to do as well during the casting of contextInfo (the compiler will help you there though).
Why not just make a wrapper C function in the Objective C class that calls the ObjC syntax and call the C function from your C program that needs to make the callback.
Related
I have a property, that in Objective-C I created like this:
self.myProperty = [[MyClass alloc] initWithCompletionBlock:^(MyClass *object) {
dispatch_async(dispatch_get_main_queue(), ^{
[self doSomethingAfterInitialization];
});
}];
And it worked great. Initialization of the MyClass object could create an indeterminate amount of time, so I passed a completionHandler in to it. When it finished, doSomethingAfterInitalization: would handle business.
Now in Swift, I'm trying to create the same object and assign it to a property, with problems.
The property never will change, so it makes sense to me to create it as a Swift constant.
So I'm trying it like this:
let myProperty = MyClass(completionBlock:{ (MyClass) -> (Void) in dispatch_async(dispatch_get_main_queue(), doSomethingAfterInitialization())})
To me that seemed like a direct translation... but the Swift compiler tells me that's not correct, via the error
Use of instance member 'doSomethingAfterInitialization' on type 'MyViewController'; did you mean to use a value of type 'MyViewController' instead?
Well that didn't help much. So instead I tried changing the call to the doSomethingAfterInitialization function to self. doSomethingAfterInitialization(), in which case I see
Value of type '(NSObject) -> () -> TodayWidgetTableViewController' has no member 'doSomethingAfterInitialization'
Any idea how I can fix this? Obviously my initializer is a little weird in the first place, so I'm wondering if this is something that doesn't really translate at all to Swift.
Are there any Objective-C runtime functions that will allow me to get a function (or block) pointer from a string identifying the function? I need some way to dynamically find and invoke a function or static method based on some form of string identifying it.
Ideally this function should be able to exist in any dynamically loaded library.
Looking at Objective-C Runtime Reference, the best bet looks like class_getClassMethod, but there don't appear to be any function-related functions in this reference. Are there other raw C ways of getting a pointer to a function by name?
if you want to invoke some static objc method, you can make it as a class method of a class
#interface MyClas : NSObject
+ (int)doWork;
#end
and call the method by
[[MyClass class] performSelector:NSSelectorFromString(#"doWork")];
if you real want to work with C-style function pointer, you can check dlsym()
dlsym() returns the address of the code or data location specified by
the null-terminated character
string symbol. Which libraries and bundles are searched depends on the handle
parameter If dlsym() is called with the special handle RTLD_DEFAULT,
then all mach-o images in the process
(except those loaded with dlopen(xxx, RTLD_LOCAL)) are searched in the order they were loaded. This
can be a costly search and should be avoided.
so you can use it to find the function pointer base on asymbol name
not sure why you want to do this, sometimes use function table can do
typedef struct {
char *name,
void *fptr // function pointer
} FuncEntry;
FuncEntry table[] = {
{"method", method},
{"method2", method2},
}
// search the table and compare the name to locate function, you get the idea
If you know method signature you can create selector to it with NSSelectorFromString function, e.g.:
SEL selector = NSSelectorFromString(#"doWork");
[worker performSelector:selector];
You may be able to do what you want with libffi. But unless you are doing something like create your own scripting language or something like that where you need to do this sort of thing a lot. It is probable overkill
I've wondered the SAME thing.. and I guess, after having researched it a bit.. there is NOT a "standard C" way to do such a thing.. (gasp).. but to the rescue? Objective C blocks!
An anonymous function.. that can be OUTSIDE any #implementation, etc...
void doCFunction() { printf("You called me by Name!"); }
Then, in your objective-C method… you can somehow "get" the name, and "call" the function...
NSDictionary *functionDict = #{ #"aName" : ^{ doCFunction(); } };
NSString *theName = #"aName";
((void (^)()) functionDict[theName] )();
Result: You called me by Name!
Loves it! 👓 ⌘ 🐻
I'm just learning Objective C (and objective-c++ for that matter) and I have an Objective-C++ class with the following constructor.
void InputManager::_init (int inputAreaX, int inputAreaY, int inputAreaWidth, int inputAreaHeight)
How do I invoke this from objective C?
This appears to be a pure C++ method so it would work exactly the same as in ordinary C++ (even in an Objective-C++ file). For instance you might have defined a variable on the stack:
InputManager mgr; // or, include constructor arguments if the class can't be default-constructed
mgr._init(x, y, w, h); // this assumes 4 variables exist with these names; use whatever parameter values you want
The name _init is a bit weird though; do you mean for this to be a constructor for the class? If so, InputManager::InputManager(int x, int y, int w, int h) should probably be defined instead.
If you actually want this class to be Objective-C only, the syntax and behavior are different.
You have two options:
Option 1.
Translate it into Objective-C only code. I'm not so good with C++, but this might be what it looks like in the .h:
-(id)initWithAreaX: (int) inputAreaX AreaY: (int) inputAreaY AreaWidth: (int) inputAreaWidth AreaHeight: (int) inputAreaHeight;
Since it looks like that's a constructor method, it would probably look like this in the implementation:
-(id)initWithAreaX: (int) inputAreaX AreaY: (int) inputAreaY AreaWidth: (int) inputAreaWidth AreaHeight: (int) inputAreaHeight {
self = [super init];
if(self) {
//Custom Initialization Code Here
_inputAreaX = inputAreaX;
_inputAreaY = inputAreaY;
_inputAreaWidth = inputAreaWidth;
_inputAreaHeight = inputAreaHeight;
}
return self;
}
And you might call it like this:
InputManager *object = [[InputManager alloc] initWithAreaX: 20 AreaY: 20 AreaWidth: 25 AreaHeight: 25];
Option 2.
The whole purpose of Objective-C++ is to allow the developer to integrate C++ and Objective-C code. You want to know how to call an Objective-C++ method from Objective-C, but the entire purpose of Objective-C++ is to integrate the two, so there's no point to trying to find a loophole to call an Objective-C++ method in a file that is otherwise completely Objective-C. So the second option is to just make the file that you want to call the Objective-C++ method in an Objective-C++ file with a ".mm" extension.
Hope this helps!
So I am trying to store a series of methods in an array (if that made sense).
void *pointer[3];
pointer[0] = &[self rotate];
pointer[1] = &[self move];
pointer[2] = &[self attack];
//...
What I am trying to do is have an array of stuff and based on the type of the object in the array, a certain method is invoked. And instead of having a bunch of if statement saying something like:
if ([[myArray objectAtIndex:0] type] == robot]) {
//Do what robots do...
}
else if (...) {
}
else {
}
And having this in a timer I was hoping to make it something like this:
pointer[[[myArray objectAtIndex:0] type]]; //This should invoke the appropriate method stored in the pointer.
Right now the code above says (the very first block of code):
Lvalue required as unary '&' operand.
If you need any clarification just ask.
Also, just to let you know all the method I am calling are type void and don't have any parameters.
You can't just make a function pointer out of an Objective-C function using the & Operator.
You'll want to look into:
#selector
NSInvocation
Blocks
Any of these can do what you want. Definitely read about selectors (the #selector compiler directive and the SEL type) if you're unfamiliar with that (it's a basic concept that you'll need a lot). Blocks are fairly new (available since Mac OS X 10.6 and iOS 4) and they'll save you a ton of work where you would have needed target/selector, NSInvocation or callback functions on earlier versions of Mac OS X and iOS.
Use function pointers if you need to pass around references to C functions but when working with methods on Objective-C objects you should really use selectors and the SEL type.
Your code would then be something like:
SEL selectors[3];
selectors[0] = #selector(rotate);
selectors[1] = #selector(move);
selectors[2] = #selector(attack);
...
[self performSelector:selectors[n]];
I'm trying to get some code going that lets me display raw trackpad data from my macbook pro, like the app FingerMgmt. Unfortunately, no one seems to have the source for FingerMgmt. I did find some other source code that kind of works, however. I was able to NSLog the data I wanted to see like this:
int callback(int device, Finger *data, int nFingers, double timestamp, int frame) {
for (int i=0; i<nFingers; i++) {
Finger *f = &data[i];
NSLog(#"Frame %7d: Angle %6.2f, ellipse %6.3f x%6.3f; "
"position (%6.3f,%6.3f) vel (%6.3f,%6.3f) "
"ID %d, state %d [%d %d?] size %6.3f, %6.3f?\n",
f->frame,
f->angle * 90 / atan2(1,0),
f->majorAxis,
f->minorAxis,
f->normalized.pos.x,
f->normalized.pos.y,
f->normalized.vel.x,
f->normalized.vel.y,
f->identifier, f->state, f->foo3, f->foo4,
f->size, f->unk2);
//todo-get data from raw C to obj-C variable
}
return 0;
}
But whenever I try to store any of the data to an Obj-c string or variable, the C code does not see the variable as having been declared. Because of this, I cannot write to any text fields or graphical displays in Obj-C, and I cannot store the data to a variable that Obj-c can access.
Basically, I need a way to write to an Obj-C variable or object from within the callback.
On a side note, I had a very similar problem with an iPhone app a while back, and I ended up fixing it by somehow declaring the app delegate within the C code and writing to or reading from the variable like this-
me.delegate=(id <UIApplicationDelegate,UITabBarControllerDelegate>)[[UIApplication sharedApplication] delegate];//allows access to the delegate within C function
me.delegate.number0=5;//writes to this variable in the delegate
For some reason, I can not seem to adapt this to my current situation. I always get the error that "me" is undeclared.
A Objective-C method can access instance variables because it is automagically passed a hidden parameter with the public name self - any reference to an instance variable, say fred, is translated by the compiler into a field reference, say self->fred (and a similar translation for property references).
For your C function callback to access the fields of any object (or call an object's methods) you need to pass the function a reference to the object. Two simple ways:
Add an argument to the function. Many C callback protocols include a general "user defined" values which is passed around as void *, if you are calling one of these pass your object reference as this value and cast it within the C function back to the correct Objective-C type.
Pass the object via a global (or file static) variable, e.g. static NSSomeType *objectForCallback;. This method works when you're stuck with an existing C callback protocol which doesn't support a user defined value. However it is not thread or re-entrant safe as you are sharing a single static variable.
In both cases make sure the objected is retain'ed if you're not using garbage collection.
In response to comment
Case 1: You will see C functions declared which (a) take a callback function and (b) a user-defined value to pass to that function on every call. For example:
typedef T ...;
T findMatching(T *buffer, // an array of T to search
size_t count, // number of items in array
int (*matcher)(T item, void *user), // user function for match, 1st arg is item, 2nd user-supplied value
void *userValue); // user-supplied value to pass to matcher
If you are faced with C function like this you can pass a (retain'ed if needed) Objective-C object as userValue and cast it back to its Objective-C type inside matcher. For example:
int myMatcher(T item, void *user)
{
NSMutableDictionary *myDictionary = (NSMutableDictionary *)user;
...
}
- (void) someMethod
{
NSMutableDictionary *sharedWithC = ...;
...
T found = findMatching(buffer, count, myMatcher, (void *)sharedWithC);
...
}
Case 2: Objective-C is (a superset of) C. You declare a global just as you would in C. For example (little checking, not thread safe):
static NSMutableDictionary *myGlobalDictionary = nil; // "static" makes the variable only visible to code in the same file
- (void) setupTheSharedDictionary
{
myGlobalDictionary = [[[NSMutableDictionary alloc] init] retain];
}
- (void) releaseTheSharedDictionary
{
if(myGlobalDictionary != nil)
{
[myGlobalDictionary release];
myGlobalDictionary = nil;
}
}
In response to second comment
I'm guessing you are trying to use some third party (Google?) code. That code defines a callback protocol - a C function type. You cannot just redefine that C function type adding an extra argument and expect the third party code to magically cope!
So unless you intend to change the C you can use the second approach - store the reference to Objective-C object in a global. In your case this will be something like:
static MT2AppDelegate *sharedWithCAppDelegateReference;
int callback(...)
{
...
[sharedWithCAppDelegateReference->L1 setStringValue:#"Hellofff"];
...
}
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
sharedWithCAppDelegateReference = self; // store so C can pick it up
...
MTRegisterContactFrameCallback(dev, callback);
...
}
But remember this is not thread or re-entrant safe - you are effectively passing a function parameter via a global variable. If you need it to be thread/re-entrant safe you need to get a bit more involved.