开发者

How do I write to an NSObject from within a C function that doesn't see Obj-C variables?

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:

  1. 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.
  2. 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.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜