jeudi 15 mars 2012

Tutorial Objective-C : Appeler du code C++ d'un programme Objective-C

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 ++





Aucun commentaire:

Enregistrer un commentaire