In my app, I have some C code that does some low level work, and needs to notify an Objective-C instance when a certain event occurs. The C function that does that low level work takes a void * to the context along with a pointer to a callback function. Then the worker calls the callback function and passes the context to it as well.
What I am trying to do is to pass a reference to "self" to that worker function, but so far I haven't had much success.
I tried
dumb casting: (void *) self,
bridged casting: (__bridge void *)self; / (__bridge_retain void*) self, CFBridgingRelease(self)
But all of that results in my app crashing.
How can I cast my self to void*? Are there any better alternatives?
Basically a bridged cast with no transfer of ownership is enough:
#implementation Foo
- (void)bar
{
void *ctx = (__bridge void *) self;
dosmthg(callback, ctx);
}
#end
static void
callback(void *ctx)
{
Foo *foo = (__bridge Foo *) ctx;
/* ... */
}
Related
I am writing an Objective-C application that uses a C Library. The issue which i am currently facing is that the C Library has a structure where some field are function pointers later used as callbacks. How can i convert an Objective-C instance method to a function pointer and pass it to the library?
You will need to provide the C callback function within the Objective-C class implementation file, and this will only work if the callback is able to use a context pointer of some sort.
So imagine the C callback signature is like this:
void myCallback(void *context, int someOtherInfo);
Then within the Objective-C class implementation file you need to use that callback to trampoline back into your Objective-C class (using the context pointer as the instance of the class to invoke):
// Forward declaration of C callback function
static void theCallbackFunction(void *context, int someOtherInfo);
// Private Methods
#interface MyClass ()
- (void)_callbackWithInfo:(int)someOtherInfo;
#end
#implementation MyClass
- (void)methodToSetupCallback
{
// Call function to set the callback function, passing it a "context"
setCallbackFunction(theCallbackFunction, self);
...
}
- (void)_callbackWithInfo:(int)someOtherInfo
{
NSLog(#"Some info: %d", someOtherInfo);
}
#end
static void theCallbackFunction(void *context, int someOtherInfo)
{
MyClass *object = (MyClass *)context;
[object _callbackWithInfo:someOtherInfo];
}
If your C callback function does not accept some sort of context info, then:
It's broken and this should be fixed/reported as a bug.
You will need to rely on storing a pointer-to-self at global, static, scope to be used by the C callback function. This will limit the number of instances of MyClass to one!
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.
I am trying to make use of -[NSObject autoContentAccessingProxy] as described at http://developer.apple.com/library/ios/documentation/Cocoa/Reference/Foundation/Classes/nsobject_Class/Reference/Reference.html#//apple_ref/occ/instm/NSObject/autoContentAccessingProxy.
The object I am trying to proxy implements the NSDiscardableContent protocol and -autoContentAccessingProxy successfully returns a non-nil value.
If, however, I try to send a message to the proxy, I always get an NSInvalidArgumentException with a reason of "*** -[NSProxy methodSignatureForSelector:] called!".
I understand that if I was writing my own NSProxy-based class, I would have to implement the -methodSignatureForSelector: method, but in this case, I am not writing the proxy, just trying to use the proxy provided by the documented method. For what it's worth, I can see that the proxy is actually of type NSAutoContentAccessingProxy, so I would expect that that class would indeed have an implementation for -methodSignatureForSelector:.
Here is a small block of code using an NSPurgeableData instance instead of my custom class. This small block has exactly the same issue.
NSPurgeableData * data = [NSPurgeableData dataWithBytes:"123" length:3];
NSLog(#"data.length = %u", data.length);
id proxyData = [data autoContentAccessingProxy];
NSLog(#"proxyData.length = %u", [proxyData length]); // throws NSInvalidArgumentException!
[data endContentAccess];
[data release];
Do I have some misunderstanding of the -autoContentAccessingProxy method here, or is it just completely broken?
You can fix this bug by reimplementing what the NSAutoContentAccessingProxy class does but without the bugs. I have written such a class: XCDAutoContentAccessingProxy. The autoContentAccessingProxy method is replaced before your main function is called; this happens in the +load method. So all you have to do is compile the following code in your application and autoContentAccessingProxy will behave as expected.
Note that unlike my previous answer, you can actually use this solution in a shipping application.
#if !__has_feature(objc_arc)
#error This code must be compiled with Automatic Reference Counting (CLANG_ENABLE_OBJC_ARC / -fobjc-arc)
#endif
#import <Foundation/Foundation.h>
#import <objc/runtime.h>
#interface XCDAutoContentAccessingProxy : NSProxy
+ (XCDAutoContentAccessingProxy *) proxyWithTarget:(id)target;
#property (nonatomic, strong) id target;
#end
#implementation XCDAutoContentAccessingProxy
#synthesize target = _target;
static id autoContentAccessingProxy(id self, SEL _cmd)
{
return [XCDAutoContentAccessingProxy proxyWithTarget:self];
}
+ (void) load
{
method_setImplementation(class_getInstanceMethod([NSObject class], #selector(autoContentAccessingProxy)), (IMP)autoContentAccessingProxy);
}
+ (XCDAutoContentAccessingProxy *) proxyWithTarget:(id)target
{
if (![target conformsToProtocol:#protocol(NSDiscardableContent)])
return nil;
if (![target beginContentAccess])
return nil;
XCDAutoContentAccessingProxy *proxy = [self alloc];
proxy.target = target;
return proxy;
}
- (void) dealloc
{
[self.target endContentAccess];
}
- (void) finalize
{
[self.target endContentAccess];
[super finalize];
}
- (id) forwardingTargetForSelector:(SEL)selector
{
return self.target;
}
- (NSMethodSignature *) methodSignatureForSelector:(SEL)selector
{
return [self.target methodSignatureForSelector:selector];
}
- (void) forwardInvocation:(NSInvocation *)invocation
{
[invocation setTarget:self.target];
[invocation invoke];
}
#end
UPDATE This bug is fixed on OS X 10.8. According to OS X Mountain Lion Release Notes:
Prior to Mac OS 10.8, -[NSObject autoContentAccessingProxy] returned an object that did not properly implement message forwarding. This proxy now behaves correctly on Mac OS 10.8.
So you need to compile the above code only if you are targeting OS X 10.7 or earlier.
You are absolutely right, -autoContentAccessingProxy is totally broken. NSAutoContentAccessingProxy is a subclass of NSProxy and should therefore implement the methodSignatureForSelector: and forwardInvocation: methods or the forwardingTargetForSelector: method if running on iOS 4 or greater.
Here is a hardcore way of fixing the NSAutoContentAccessingProxy class by adding the methodSignatureForSelector: and forwardInvocation: methods at runtime. Just add the following to your project (do not compile this with ARC).
#import <mach-o/dyld.h>
#import <mach-o/nlist.h>
__attribute__((constructor)) void FixAutoContentAccessingProxy(void);
static id _target(id autoContentAccessingProxy);
static NSMethodSignature *NSAutoContentAccessingProxy_methodSignatureForSelector(id self, SEL _cmd, SEL selector);
static void NSAutoContentAccessingProxy_forwardInvocation(id self, SEL _cmd, NSInvocation *invocation);
__attribute__((constructor)) void FixAutoContentAccessingProxy(void)
{
Class NSAutoContentAccessingProxy = objc_lookUpClass("NSAutoContentAccessingProxy");
Method methodSignatureForSelector = class_getInstanceMethod([NSObject class], #selector(methodSignatureForSelector:));
Method forwardInvocation = class_getInstanceMethod([NSObject class], #selector(forwardInvocation:));
class_addMethod(NSAutoContentAccessingProxy, #selector(methodSignatureForSelector:), (IMP)NSAutoContentAccessingProxy_methodSignatureForSelector, method_getTypeEncoding(methodSignatureForSelector));
class_addMethod(NSAutoContentAccessingProxy, #selector(forwardInvocation:), (IMP)NSAutoContentAccessingProxy_forwardInvocation, method_getTypeEncoding(forwardInvocation));
}
static id _target(id autoContentAccessingProxy)
{
static uint32_t targetIvarOffset;
static dispatch_once_t once;
dispatch_once(&once, ^{
struct nlist symlist[] = {{"_OBJC_IVAR_$_NSAutoContentAccessingProxy._target", 0, 0, 0, 0}, NULL};
for(uint32_t i = 0; i < _dyld_image_count(); i++)
{
if (nlist(_dyld_get_image_name(i), symlist) == 0 && symlist[0].n_value != 0)
{
uint32_t *_OBJC_IVAR_NSAutoContentAccessingProxy_target = (uint32_t*)((uint32_t)_dyld_get_image_header(i) + symlist[0].n_value);
targetIvarOffset = *_OBJC_IVAR_NSAutoContentAccessingProxy_target;
break;
}
}
});
return *(id*)((uint32_t)autoContentAccessingProxy + targetIvarOffset);
}
static NSMethodSignature *NSAutoContentAccessingProxy_methodSignatureForSelector(id self, SEL _cmd, SEL selector)
{
return [_target(self) methodSignatureForSelector:selector];
}
static void NSAutoContentAccessingProxy_forwardInvocation(id self, SEL _cmd, NSInvocation *invocation)
{
[invocation setTarget:_target(self)];
[invocation invoke];
}
This workaround should be used only to demonstrate how NSAutoContentAccessingProxy is broken. Anyway this will only work on the simulator because the nlist call will fail on the device. You could actually make it work on the device by using APEFindSymbol from APELite-arm instead of nlist but I don't recommend it.
You should definitely file a bug report about it to Apple.
I have an Obj-C object with a bunch of methods inside of it. Sometimes a method needs to call another method inside the same object. I can't seem to figure out how to get a C method to call a Obj-C method...
WORKS: Obj-C method calling an Obj-C method:
[self objCMethod];
WORKS: Obj-C method calling a C method:
cMethod();
DOESN'T WORK: C method calling an Obj-C method:
[self objCMethod]; // <--- this does not work
The last example causes the compiler spits out this error:
error: 'self' undeclared (first use in this function)
Two questions. Why can't the C function see the "self" variable even though it's inside of the "self" object, and how do I call it without causing the error? Much thanks for any help! :)
In order for that to work, you should define the C method like this:
void cMethod(id param);
and when you call it, call it like this:
cMethod(self);
then, you would be able to write:
[param objcMethod];
In your cMethod.
This is because the self variable is a special parameter passed to Objective-C methods automatically. Since C methods don't enjoy this privilege, if you want to use self you have to send it yourself.
See more in the Method Implementation section of the programming guide.
I know your question is already answered by Aviad but just to add to the info since this is not unrelated:
In my case I needed to call an Objective-C method from a C function that I did not call myself (a Carbon Event function triggered by registering a global hotkey event) so passing self as a parameter was impossible. In this particular case you can do this:
Define a class variable in your implementation:
id thisClass;
Then in your init method, set it to self:
thisClass = self;
You can then call Objective-C methods from any C function in the class without the need to pass self as a parameter to the function:
void cMethod([some parameters]) {
[thisClass thisIsAnObjCMethod];
}
C function is not "inside of the self object". In fact, nothing is.
Objective-C methods effectively get self as an implicit argument, with magic done under the hood. For plain C functions, they aren't associated with any class or object, and there's no call magic, so no self. If you need it, you need to pass it to your C function explicitly as an argument.
To be totally truthful, there is no such thing as a C method. C has functions. To illustrate the difference, look at the following examples:
This is a working C program that defines a type and two functions that go along with it:
#include <stdio.h>
typedef struct foo_t {
int age;
char *name;
} Foo;
void multiply_age_by_factor(int factor, Foo *f) {
f->age = f->age * factor;
}
void print_foo_description(Foo f) {
printf("age: %i, name: %s\n", f.age, f.name);
}
int main() {
Foo jon;
jon.age = 17;
jon.name = "Jon Sterling";
print_foo_description(jon);
multiply_age_by_factor(2, &jon);
print_foo_description(jon);
return 0;
}
Here is an Objective-C implementation of that program:
#import <Foundation/Foundation.h>
#interface Foo : NSObject {
NSUInteger age;
NSString *name;
}
#property (nonatomic, readwrite) NSUInteger age;
#property (nonatomic, copy) NSString *name;
- (void)multiplyAgeByFactor:(NSUInteger)factor;
- (NSString *)description;
- (void)logDescription;
#end
#implementation Foo
#synthesize age;
#synthesize name;
- (void)multiplyAgeByFactor:(NSUInteger)factor {
[self setAge:([self age] * factor)];
}
- (NSString *)description {
return [NSString stringWithFormat:#"age: %i, name: %#\n", [self age], [self name]];
}
- (void)logDescription {
NSLog(#"%#",[self description]);
}
#end
int main (int argc, const char * argv[]) {
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
Foo *jon = [[[Foo alloc] init] autorelease];
[jon setAge:17];
[jon setName:#"Jon Sterling"];
[jon logDescription];
[jon multiplyAgeByFactor:2];
[jon logDescription];
[pool drain];
return 0;
}
The output of the pure C program was:
age: 17, name: Jon Sterling
age: 34, name: Jon Sterling
The output of the Objective-C program was:
2009-08-25 17:40:52.818 test[8963:613] age: 17, name: Jon Sterling
2009-08-25 17:40:52.828 test[8963:613] age: 34, name: Jon Sterling
The only difference is all the junk that NSLog puts before the text. The functionality is exactly the same. So, in C, you can use something sort of like methods, but they are really just functions that include a pointer to a struct.
I don't think this answered your original question, but it did clear up some terminology issues you appear to have been having.
Another option to the answers given thus far is to use the objc_msgSend() function provided by the Objective-C runtime.
I understand the basic syntax of Objective-C, have installed Cygwin, and want to experiment. However i am unsure of two things:
What i would import, and
what the primitive type names are.
Can someone help me?
The only object you can inherit from is called Object. Bare in mind that this offers nowhere near the same amount of functionality as NeXTStep's or Cocoa's NSObject. Object does not even have anything like reference counting. In order to get the same sort of reference counting memory management that NSObject has you'll need to implement it yourself.
#import <objc/Object.h>
#interface MyObject : Object
{
int retainCount;
}
- (id) retain;
- (int) retainCount;
- (void) release;
#end
#implementation MyObject
+ (MyObject *) alloc
{
// In Cocoa, allocated objects have an implicit retain.
MyObject *anObject = [super alloc];
anObject->retainCount = 1;
return anObject;
}
- (void) release
{
retainCount--;
if (retainCount == 0)
[self free];
}
- (id) retain
{
retainCount++;
return self;
}
- (int) retainCount
{
return retainCount;
}
#end
int main (int argc, char *argv[])
{
MyObject *test = [[MyObject alloc] init];
[test retain];
[test release];
[test release];
// (test should be deallocated now)
return 0;
}
When linking, you have to make sure you link with -lobjc, this is where the definition of Object lies (I think).
The other big catch is with static string instances, i.e. strings in code that appear #"like this". With the GNU runtime, static instances of strings need to have a particular ivar layout, which is:
// Let's assume that we have a protocol <MyObject> that defines all the basic methods
// like retain, release etc. In this case, these should be no-ops because the static
// string is never deallocated. In Cocoa, there is a protocol <NSObject> which provides
// the same common methods.
#interface MyStaticStringClass : Object <MyObject>
{
char *str;
unsigned len;
}
- (const char *) cString;
#end
#implementation MyStaticStringClass
- (void) retain
{
return;
}
- (id) retain
{
return self;
}
- (int) retainCount
{
return INT_MAX;
}
- (const char *) cString
{
return str;
}
#end
int main (int argc, char *argv[])
{
id aString = #"Hello world!";
fprintf (stdout, "aString has the contents: %s\n", [aString cString]);
return 0;
}
When compiling, you can use the flag -fconstant-string-class=MyStaticStringClass. You can provide whatever methods you like for the string class but it must have only two ivars and they must be in the right order. If you don't want to use Objective-C style strings, then you don't have to define a static string class. If you do define a static string class it should be able to replicate the behaviour of your dynamic string class (i.e. string objects that are allocated during run time) so that you can use either in a given situation.
For command-line utilities and basic apps I choose not to use Cocoa or GNUstep but rather define my own classes. It has many drawbacks, but I find that object abstraction and metamorphism in Objective-C is much easier to implement than in the other languages that I program in.