如何从没有看到Obj-C变量的C函数中写入NSObject?

wya*_*ger 3 c macos objective-c multi-touch

我正在尝试使用一些代码来让我显示来自我的macbook pro的原始触控板数据,比如应用程序FingerMgmt.不幸的是,似乎没有人拥有FingerMgmt的来源.但是,我确实找到了一些其他有用的源代码.我能够NSLog我想看到的数据如下:

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;
Run Code Online (Sandbox Code Playgroud)

}

但每当我尝试将任何数据存储到Obj-c字符串或变量时,C代码都不会将变量视为已声明.因此,我无法写入Obj-C中的任何文本字段或图形显示,也无法将数据存储到Obj-c可以访问的变量中.

基本上,我需要一种方法从回调中写入Obj-C变量或对象.

一方面,我在一段时间内与iPhone应用程序有一个非常类似的问题,我最终通过某种方式在C代码中声明应用程序委托并写入或读取变量,这样修复它 -

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
Run Code Online (Sandbox Code Playgroud)

出于某种原因,我似乎无法适应我目前的情况.我总是得到"我"未宣布的错误.

CRD*_*CRD 6

Objective-C方法可以访问实例变量,因为它会自动传递一个带有公共名称的隐藏参数self- 例如,对实例变量的任何引用fred都由编译器转换为字段引用,比如说self->fred(和属性引用的类似转换) ).

要使C函数callback访问任何对象的字段(或调用对象的方法),您需要将函数传递给对象.两种简单方法:

  1. 在函数中添加一个参数.许多C回调协议包括一般的"用户定义"值void *,如果您正在调用其中一个,则传递您的对象引用作为此值并将其在C函数中转换回正确的Objective-C类型.
  2. 通过全局(或文件静态)变量传递对象,例如static NSSomeType *objectForCallback;.当您遇到不支持用户定义值的现有C回调协议时,此方法有效.但是,由于您共享一个静态变量,因此它不是线程或可重入的安全.

在这两种情况下,retain如果您没有使用垃圾收集,请确保对象已被删除.

回应评论

情况1:您将看到声明的C函数,其中(a)采用回调函数,(b)在每次调用时传递给该函数的用户定义值.例如:

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
Run Code Online (Sandbox Code Playgroud)

如果您面对像这样的C函数,您可以传递一个(retain如果需要的话)Objective-C对象,userValue并将其转换回其Objective-C类型matcher.例如:

int myMatcher(T item, void *user)
{
    NSMutableDictionary *myDictionary = (NSMutableDictionary *)user;
    ...
}

- (void) someMethod
{
    NSMutableDictionary *sharedWithC = ...;
    ...
    T found = findMatching(buffer, count, myMatcher, (void *)sharedWithC);
    ...
}
Run Code Online (Sandbox Code Playgroud)

案例2:Objective-C (C 的超集)C.你像在C中一样声明一个全局.例如(小检查,而不是线程安全):

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;
    }
}
Run Code Online (Sandbox Code Playgroud)

回应第二条评论

我猜你正试图使用​​一些第三方(谷歌?)代码.该代码定义了一个回调协议 - 一个C函数类型.你不能只重新定义那个添加额外参数的C函数类型,并期望第三方代码能够神奇地应对!

因此,除非您打算更改C,否则可以使用第二种方法 - 在全局中存储对Objective-C对象的引用.在你的情况下,这将是这样的:

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);
    ...
}
Run Code Online (Sandbox Code Playgroud)

但请记住,这不是线程或重入安全 - 您实际上是通过全局变量传递函数参数.如果你需要它是线程/可重入的安全,你需要更多参与.