2009-04-29 6 views
37

Я пишу класс Objective-C, но он использует API, написанный на C. Это в основном отлично, поскольку смешивание вызовов C с вызовами Objective-C вызывает несколько проблем.Смешивание функций C в классе Objective-C

Однако один из вызова API требует вызова обратно метод (пример):

success = CFHostSetClient(host, MyCFHostClientCallBack, &context); 

Где MyCFHostClientCallBack функция C определяется следующим образом:

static void MyCFHostClientCallBack(CFHostRef host, CFHostInfoType typeInfo, const CFStreamError *error, void *info); 
  1. Может/Как я вместо этого вместо метода Objective-C?
  2. Могу ли я смешивать функции C с вызовами Objective-C?
  3. Как использовать функции C с помощью методов Objective-C?

ответ

48

Смешивание C и Objective-C методы и функции можно, вот простой пример, который использует SQLite API в iPhone App: (course site)

Загрузите Zip file (09_MySQLiteTableView.zip)

функции C должны быть declar ed за пределами @implementation в файле Objective-C (.m).

int MyCFunction(int num, void *data) 
{ 
    //code here... 
} 

@implementation 

- (void)MyObjectiveCMethod:(int)number withData:(NSData *)data 
{ 
     //code here 
} 

@end 

Поскольку функция C находится вне @implementation она не может вызывать такие методы, как

[self doSomething] 

и не имеет доступа к Ивар.

Это может быть выполнено до тех пор, пока функция обратного вызова принимает параметр типа или context, как правило, типа void*. Это можно использовать для отправки любого объекта Objective-C в функцию C.

Как и в случае с sample code, это может быть связано с обычными операциями Objective-C.

Кроме того, пожалуйста, этот ответ: Mixing C functions in an Objective-C class

+26

Функции C не должны находиться за пределами '@ implementation'. – 2011-04-17 12:11:17

+12

@Bavarious: компилятор позволяет вам уйти с функциями внутри '@ implementation', но он по-прежнему не является частью' @ implementation', поскольку функции не могут принадлежать классу. В качестве стиля я оставляю его вне '@ implementation' и рекомендую другим делать то же самое, чтобы сделать это ясно. –

+20

На самом деле функции C внутри блоков @implementation имеют уникальное свойство иметь доступ к закрытым и защищенным ivars напрямую. Таким образом, по собственному опыту, стало сильным идиомом размещать функции C, которые «принадлежат» классу внутри соответствующей реализации. Я бы рекомендовал обновить ваш ответ. –

5

Что я всегда нашел полезным в этой ситуации, это сделать обертку Obj-C поверх C API. Реализуйте то, что вам нужно для использования функций C, и постройте класс Objective-C (или два) поверх него, так что это все, что увидит внешний мир. Например, в случае обратного вызова вы можете создать функцию C, которая вызывает методы делегирования Obj-C на других объектах.

25

Для вызова кода Objective-C от C обратного вызова я бы использовать что-то вроде:

void * refToSelf; 
int cCallback() 
{ 
    [refToSelf someMethod:someArg]; 
} 

@implementation SomeClass 
- (id) init 
{ 
    self = [super init]; 
    refToSelf = self; 
} 
- (void) someMethod:(int) someArg 
{ 
} 
+8

Только одно дополнение: многие обратные вызовы позволяют указать «пользовательские данные»; в этом случае указатель объекта может использоваться как пользовательские данные (и вам больше не нужна глобальная переменная refToSelf). Возможно, ваша функция обратного вызова поддерживает «пользовательские данные» в указателе информации. – ashcatch

+0

Я получаю предупреждения о утечке памяти во время работы с поддержкой ARC с использованием вышеуказанного кода. http://stackoverflow.com/questions/11840943/runtime-memory-leaked-warnings-when-executing-objective-c-code-within-c-code-wit – docchang

+2

Это ошибочная реализация. Это ПРИНИМАЕТ, у вас есть только один экземпляр ComeClass. void * refToSelf; является статической/глобальной переменной. Каждый раз, когда вы [[SomeClass alloc] init], ваш refToSelf будет перезаписан последним созданным экземпляром. CCallback НЕ будет вызывать правильный SomeClass, но, скорее, всегда создан последний. Кроме того, он выйдет из строя, когда будет выпущен последний созданный SomeClass (по крайней мере, в коде выше), потому что вы не очищаете refToSelf по dealloc SomeClass. –

8

Может/Как вызвать метод Objective-C вместо этого?

Вы не можете.

Могу ли я использовать функцию C в моем вызове Objective-C?

Да. Напишите функцию C и используйте ее как обратный вызов функции CF.

Как скомбинировать функцию C с методами Objective-C?

Вы можете установить self в качестве указателя info в свою контекстную структуру. Это будет передано на обратный вызов. Затем, в обратный вызов, бросить info указатель обратно id:

MyClass *self = (id)info; 

Вы можете отправить self сообщения. Однако вы по-прежнему не можете напрямую обращаться к переменным экземпляра, поскольку функция C находится вне раздела @implementation. Вы должны будете сделать их свойствами. Вы можете сделать это с помощью class extension. (Вопреки тому, что говорится в этом документе, вы не объявляете расширение внутри @implementation, но в том же файле вместе с ним, как правило, прямо над ним.)

Смежные вопросы