Метод Objective C может обращаться к переменным экземпляра, потому что ему автоматически передается скрытый параметр с открытым именем self
- любая ссылка на переменную экземпляра, скажем, fred
, переводится компилятором в ссылку на поле, скажем self->fred
(и аналогичный перевод для ссылок на свойства).
Для того, чтобы ваша функция C callback
могла получить доступ к полям любого объекта (или вызвать методы объекта), вам нужно передать функции ссылку на объект. Два простых способа:
- Добавить аргумент в функцию. Многие протоколы обратного вызова C включают общие «определяемые пользователем» значения, которые передаются как
void *
, если вы вызываете один из них, передаете ссылку на объект в качестве этого значения и приводите ее в функции C обратно к правильному типу Objective-C .
- Передать объект через глобальную (или статическую) переменную, например,
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);
...
}
Но помните, что это не поток и не безопасно для повторного входа - вы фактически передаете параметр функции через глобальную переменную. Если вам нужно, чтобы он был безопасным для потоков / повторного входа, вам нужно немного больше участвовать.