Call obj-c object from a c function
I have a function that executed in c. When a certain condition is met I want to change the state of a UIButton. I was trying to dispatch an NSNotification but that doesnt work.
What would be a good way to send a message to an obj-c object from a c function?
Ideally I 开发者_运维知识库would like to somehow be able to use NSNotification
The C Code needs to be inside of a .m file. If it is not then add a C callback function inside your .m that can post your notification or do something else for you. Here is an example of accessing the Objective-C class that calls a C function outside of a .m file.
//SomeCCode.c
void someCFunction(int somevar, void (callback) (void*) , void *context)
{
doSomething(somevar);
callback(context);
}
//SomeClass.m
void someCCallbackInObjC(void *context)
{
SomeClass *myclass = (SomeClass*)context;
//Access my class or just post notification
}
@implementation SomeClass
...
-(void)someMethod
{
someCFunction(0, someCCallbackInObjC, self);
}
...
@end
Simply compile your C files as Objectice-C; and access NSNotificationCenter as usual.
Unlike C++, Objective-C imparts no compatibility pitfalls on C code. All and any C code is also valid Objective-C code, assuming the underlying standard used is the same.
Edit: To elaborate: as long as you use the Objective-C compiler; there's no difference between what you can do in a method and a function; except that self
and super
aren't available for use in C functions unless you define them yourself.
Reedit: In order to define self in a C function; simply define it as follows:
notifyingFunction(id self, /* other arguments */);
and pass any appropriate self
when calling the function.
I've spent quite a while to find the solution to post notifications from C to Objective C for my OS X app developed with XCode 5 on Mavericks. Joe's answer was the only working solution for me with XCode 5 on Mavericks. I had to add bridging though. So, my app has code similar to the following:
//SomeCCode.c - no changes here
void someCFunction(int somevar, void (callback) (void*) , void *context)
{
doSomething(somevar);
callback(context);
}
//SomeClass.m
void someCCallbackInObjC(void *context)
{
// change #1: added __bridge in type cast
SomeClass *myclass = (__bridge SomeClass*)context;
//Access my class or just post notification
}
@implementation SomeClass
...
-(void)someMethod
{
// change #2: added the type cast with __bridge for self
someCFunction(0, someCCallbackInObjC, (__bridge void*) (self));
}
...
@end
I was messing around a lot with this so
just in addition:
I am using a c unit, which i don't want to rename to *.m files. And I need a log called from there.
No wrappers could help me to avoid linker errors.
So I used the following pattern:
I made hpp and cpp files
Added an extern variable - pointer to a function to header:
extern void (*transLogFun) (const char *,...);
and its definition to cpp file
void (*transLogFun) (const char *,...) = NULL;
Then i created an h and mm file: h:
#import <UIKit/UIKit.h>
#import "fff.hpp"
void ioslogfun(const char *s, ...);
In mm file i wrote a function and a class with its object like this:
#import "zzz.h"
#import <Foundation/Foundation.h>
void ioslogfun(const char *s, ...){
va_list vl;
va_start(vl,s);
char *str;
vasprintf(&str,s,vl);
va_end(vl);
NSLog([NSString stringWithUTF8String:str]);
free(str);
}
class Fff{
public:
Fff(){
transLogFun = &ioslogfun;
}
};
Fff initiator;
And where-ever i called the transLogFun(...) it worked fine.
精彩评论