Как мне написать в NSObject из функции C, которая не видит переменные Obj-C? - PullRequest
3 голосов
/ 27 апреля 2011

Я пытаюсь запустить некоторый код, который позволяет отображать необработанные данные трекпада из моего 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;

}

Но всякий раз, когда я пытаюсь сохранить какие-либо данные в строку или переменную 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

Почему-то я не могу приспособить это к моей текущей ситуации.Я всегда получаю ошибку, что «я» не объявлено.

1 Ответ

6 голосов
/ 27 апреля 2011

Метод Objective C может обращаться к переменным экземпляра, потому что ему автоматически передается скрытый параметр с открытым именем self - любая ссылка на переменную экземпляра, скажем, fred, переводится компилятором в ссылку на поле, скажем self->fred (и аналогичный перевод для ссылок на свойства).

Для того, чтобы ваша функция C callback могла получить доступ к полям любого объекта (или вызвать методы объекта), вам нужно передать функции ссылку на объект. Два простых способа:

  1. Добавить аргумент в функцию. Многие протоколы обратного вызова C включают общие «определяемые пользователем» значения, которые передаются как void *, если вы вызываете один из них, передаете ссылку на объект в качестве этого значения и приводите ее в функции C обратно к правильному типу Objective-C .
  2. Передать объект через глобальную (или статическую) переменную, например, static NSSomeType *objectForCallback;. Этот метод работает, когда вы застряли с существующим протоколом обратного вызова C, который не поддерживает пользовательское значение. Однако он не является потокобезопасным или безопасным для повторного входа, поскольку вы совместно используете одну статическую переменную.

В обоих случаях убедитесь, что объект возражения retain 'ed, если вы не используете сборщик мусора.

В ответ на комментарий

Случай 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

Если вы сталкиваетесь с подобной функцией C, вы можете передать (retain 'ed, если необходимо) объект 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);
    ...
}

Случай 2: Objective-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;
    }
}

В ответ на второй комментарий

Полагаю, вы пытаетесь использовать какой-либо сторонний (Google?) Код. Этот код определяет протокол обратного вызова - тип функции 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);
    ...
}

Но помните, что это не поток и не безопасно для повторного входа - вы фактически передаете параметр функции через глобальную переменную. Если вам нужно, чтобы он был безопасным для потоков / повторного входа, вам нужно немного больше участвовать.

...