44 votes

Mélange de fonctions C dans une classe Objective-C

Je suis en train d'écrire une classe Objective-C mais elle utilise une API écrite en C. C'est plutôt bien, car mélanger des appels C avec des appels Objective-C pose peu de problèmes.

Cependant, l'un des appels API nécessite une méthode de rappel (exemple) :

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

Dónde MyCFHostClientCallBack est une fonction C définie comme suit :

static void MyCFHostClientCallBack(CFHostRef host, CFHostInfoType typeInfo, const CFStreamError *error, void *info);
  1. Puis-je/comment puis-je appeler une méthode Objective-C à la place de celle-ci ?
  2. Puis-je/doit-je mélanger une fonction C avec mon appel Objective-C ?
  3. Comment mélanger les fonctions C avec les méthodes Objective-C ?

52voto

rjstelling Points 12180

Mélanger les méthodes et fonctions C et Objective-C est possible, voici un exemple simple qui utilise l'API SQLite dans une application iPhone : ( site de cours )

http://stanford.edu/class/cs193p/cgi-bin/drupal/system/files/sample_code/09_MySQLiteTableView.zip

Les fonctions C doivent être déclarées en dehors du @implementation dans un fichier Objective-C (.m).

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

@implementation

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

@end

Parce que la fonction C est en dehors du @implementation il ne peut pas appeler des méthodes comme

[self doSomething]

et n'a pas accès aux ivars.

Cela peut être contourné tant que la fonction de rappel prend une valeur de userInfo o context paramètre de type, normalement de type void* . Ceci peut être utilisé pour envoyer n'importe quel objet Objective-C à la fonction C.

Comme dans le exemple de code Il est possible de le manipuler avec des opérations Objective-C normales.

En outre, veuillez lire cette réponse : Mélange de fonctions C dans une classe Objective-C

33 votes

Les fonctions C n'ont pas besoin d'être à l'extérieur @implementation .

13 votes

@Bavarious : Le compilateur permet de s'affranchir des fonctions à l'intérieur. @implementation mais il ne fait toujours pas partie de l @implementation Les fonctions ne peuvent pas appartenir à une classe. Pour des raisons de style, je le laisse à l'extérieur de la classe @implementation et recommander aux autres de faire de même, pour que cela soit clair.

24 votes

En fait, les fonctions C à l'intérieur des blocs @implementation ont la propriété unique de pouvoir accéder directement aux ivars privés et protégés. Ainsi, d'après ma propre expérience, il est devenu courant de placer les fonctions C qui "appartiennent" à une classe à l'intérieur de l'implémentation correspondante. Je vous recommande de mettre à jour votre réponse.

27voto

diciu Points 18634

Pour appeler du code Objective-C depuis un callback C, j'utiliserais quelque chose comme :

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

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

8 votes

Juste un ajout : de nombreux callbacks permettent de spécifier des "données utilisateur" ; dans ce cas, le pointeur d'objet pourrait être utilisé comme données utilisateur (et vous n'avez plus besoin de la variable globale refToSelf). Il se peut que votre fonction de rappel prenne en charge les "données utilisateur" dans le pointeur d'information.

0 votes

Je reçois des avertissements de fuites de mémoire à l'exécution avec ARC activé en utilisant le code ci-dessus. stackoverflow.com/questions/11840943/

2 votes

Il s'agit d'une mise en œuvre boguée. Elle suppose que vous n'avez qu'une seule instance de ComeClass. void *refToSelf ; est une variable statique/globale. Chaque fois que vous [[SomeClass alloc] init] votre refToSelf sera écrasé par la dernière instance créée. Le cCallback n'appellera PAS la bonne SomeClass, mais toujours la dernière créée. De plus, il y aura un crash lorsque la dernière SomeClass créée sera libérée (au moins dans le code ci-dessus) parce que vous n'effacez pas le refToSelf lors du dealloc de la SomeClass.

8voto

Peter Hosey Points 66275

Puis-je/comment puis-je appeler une méthode Objective-C à la place de celle-ci ?

Vous ne pouvez pas.

Puis-je/doit-je mélanger une fonction C avec mon appel Objective-C ?

Oui. Écrivez une fonction C et utilisez-la comme rappel de la fonction CF.

Comment mélanger les fonctions C avec les méthodes Objective-C ?

Vous pouvez définir self comme le info dans votre structure de contexte. Il sera transmis au callback. Ensuite, dans le callback, mettez le info pointeur vers id :

MyClass *self = (id)info;

Vous pouvez alors envoyer self messages. Cependant, vous ne pouvez toujours pas accéder directement aux variables d'instance, car une fonction C se situe en dehors de l'environnement de l'utilisateur. @implementation section. Vous devrez en faire des propriétés. Vous pouvez le faire avec un extension de classe . (Contrairement à ce que dit ce document, vous ne déclareriez pas l'extension à l'intérieur de . @implementation mais dans le même dossier que lui, généralement juste au-dessus).

5voto

Marc Charbonneau Points 30464

Ce que j'ai toujours trouvé utile dans cette situation est de créer une enveloppe Obj-C au-dessus de l'API C. Implémentez ce dont vous avez besoin à l'aide de fonctions C, et construisez une classe Objective-C (ou deux) par-dessus, de façon à ce que le monde extérieur ne voie que ça. Par exemple, dans le cas d'un callback comme celui-ci, vous pourriez créer une fonction C qui appelle les méthodes déléguées Obj-C sur d'autres objets.

0voto

crifan Points 1242

.m appeler une fonction à l'intérieur .c :

  • CrifanLib.h

    ifndef CrifanLib_h

    define CrifanLib_h

    include <stdio.h>

    void fileModeToStr(mode_t mode, char * modeStrBuf);

    endif / CrifanLib_h /

  • CrifanLib.c

    include "CrifanLib.h"

    include <stdbool.h>

    void fileModeToStr(mode_t mode, char * modeStrBuf) { // buf must have at least 10 bytes const char chars[] = "rwxrwxrwx"; for (size_t i = 0; i < 9; i++) { // buf[i] = (mode & (1 << (8-i))) ? chars[i] : '-'; bool hasSetCurBit = mode & (1 << (8-i)); modeStrBuf[i] = hasSetCurBit ? chars[i] : '-'; } modeStrBuf[9] = '\0'; }

appelé par Objective-C 's .m :

#include “CrifanLib.h"

@interface JailbreakDetectionViewController ()

@end

@implementation JailbreakDetectionViewController
…

char* statToStr(struct stat* statInfo){
    char stModeStr[10];
    fileModeToStr(statInfo->st_mode, stModeStr);
...
}

...

fait.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X