Ce tutorial a pour but d'expliquer
comment appeler du code C++ d'une application écrite en Objective-C, voir avec le framework Cocoa ou Cocoa Touch.
Il est fort à parier que bon nombre d'entreprises ayant des applications
écrites en C++, les porteront vers Mac OS X ou iOS.
Pour ce faire il est fort utile de créer des applications bénéficiant d'une interface graphique écrite avec COCOA et l'outil Interface Builder, mais dont le coeur est en C++.
Le tutorial :
1) Créer un projet avec XCode (ici XCode 4) du type console
2) Dans notre projet il y aura les fichiers suivants :
a) Le fichier 'main.m' sera du pur Objective-C
b) Les fichiers 'Wrapper.h' et 'Wrapper.mm' sera la classe Objective-C intégrant et appelant du code C++
c) Les fichiers 'CATPeageSimulation.h' et 'CATPeageSimulation.cpp' représentant le pur code C++, sans trace d'Objective-C
3) Le fichier 'main.m' (en Objective-C)
#import "WrapperCPP.h"
// SOURCE Objective-C
int main (int argc, const char * argv[])
{
@autoreleasepool {
NSLog(@"Programme Objective-C appelant du code C++");
WrapperCPP * pw = [[WrapperCPP alloc] init];
[pw launchSimu];
}
return 0;
}
Ci-dessus le source du main écrit en Objective-C.
On constate la création d'un objet représenté par le pointeur 'pw'.
Ici pas de 'release' nous disposons d'un GC.
4) Le "wrapper" : fichiers 'WrapperCPP.h" et "WrapperCPP.mm"
WrapperCPP.h
// Prototype Objective-C de la classe WrapperCPP
@interface WrapperCPP : NSObject
-(void) launchSimu;
@end
WrapperCPP.mm
#import "WrapperCPP.h"
#include "CATPeageSimulation.h"
// Implementation Objective-C
@implementation WrapperCPP
// Implementation du message Objective-C
-(void) launchSimu {
// ######################################
// ICI LE CODE C++
CATPeageSimulation objet1;
int ret = objet1.RunSimu();
if( ret )
std::cout << "echec au retour de simu" << std::endl;
// ######################################
}
@end
Ci-dessus le fichier "mm" obligatoire pour intégrer dans des classes Objective-C du code C++.
5) Le code C++ (uniquement du code C++)
CATPeageSimulation.h
#ifndef Objective_C_AppelerCPP_ltm_CATPeageSimulation_h
#define Objective_C_AppelerCPP_ltm_CATPeageSimulation_h
#define NUM_THREADS 256
class CATPeageSimulation {
private:
public:
CATPeageSimulation();
virtual ~CATPeageSimulation();
int RunSimu();
};
void * ThreadVoiture( void * );
int Random( int, int );
#endif
CATPeageSimulation.cpp
#include "CATPeageSimulation.h"
pthread_mutex_t mutex_caisse;
// Thread voiture
void * ThreadVoiture( void * threadid ) {
long tid = (long)threadid;
printf( "Thread voiture, thread #%ld, je fais la queue\n", tid );
pthread_mutex_lock( &mutex_caisse );
printf( "Thread voiture, thread #%ld, je paye\n", tid );
// Random( x, y ) -> la valeur va être comprise entre x et y en seconde(s)
sleep( Random( 10, 20 ) );
printf( "Thread voiture, thread #%ld, j'ai payé\n", tid );
sleep(1);
pthread_mutex_unlock( &mutex_caisse );
pthread_exit( NULL );
}
int Random( int min, int max ) {
return (min +( rand() % (max - min + 1 )));
}
// ctor
CATPeageSimulation::CATPeageSimulation() {
}
// dtor
CATPeageSimulation::~CATPeageSimulation() {
}
int CATPeageSimulation::RunSimu() {
pthread_t threads[NUM_THREADS];
int rc = 0, t = 0;
unsigned int nbr_c = 1, nbr_v;
printf("\n\nEntrez le nbr de voiture se présentant au peage ? ");
scanf( "%d", &nbr_v );
if( nbr_c <= 0 || nbr_v <=0 ) {
printf( "chiffre négatif\n" );
return 1;
}
printf ( "nbr de caisse = %d\n", nbr_c );
if( pthread_mutex_init( &mutex_caisse, NULL ) ) {
printf( "init mutex failed -> exit\n" );
return 1;
}
for ( t=0; t < nbr_v; t++ ) {
rc = pthread_create( &threads[0], NULL, ThreadVoiture, (void *)t );
}
for ( t=0; t < nbr_v; t++ ) {
pthread_join( threads[t], NULL);
printf( "thread %d joined\n", t );
}
pthread_mutex_destroy( &mutex_caisse );
printf( "Fin de simulation !\n" );
return 0;
}
Fin du tutorial
En résumé :
Un programme 'main.m' appelle une classe écrite en Objective-C Wrapper.mm qui appelle du pur code C++.
main.m : code Objective-C uniquement
Wrapper.mm : Mélange d'Objective-C appelant du code C++
CATPeageSimulation.cpp : Pur code C ++