Utiliser C ++ avec Cocoa au lieu d'Objective-C?


122

Je voudrais écrire des applications qui utilisent C ++ et les frameworks Cocoa car Apple ne rend pas compatible Carbon 64 bits. C ++ semble être assez simple dans son implémentation sous Linux et Windows, mais sur Mac OS X, il semble que des morceaux de code supplémentaires spécifiques à Apple soient nécessaires (comme un wrapper Obj-C). Il semble également qu'Apple oblige les développeurs à écrire en Objective-C plutôt qu'en C ++, bien que je puisse me tromper.

J'essaie de trouver un chemin pour écrire du code sur le Mac qui serait facile à garder multi-plateforme. Avoir à écrire du code en C ++ pour Linux / Windows puis à réécrire de grandes portions en Objective-C serait très inefficace.

Existe-t-il un moyen d'écrire du code en C ++ qui sera pris en charge à l'avenir et pris en charge dans Xcode? De plus, si cela est possible, comment pourrais-je mélanger C ++ et Objective-C dans Xcode? Merci.

Réponses:


110

Vous ne pouvez pas écrire une application Cocoa entièrement en C ++. Cocoa s'appuie fortement sur les capacités de liaison tardive d'Objective-C pour bon nombre de ses technologies de base telles que les liaisons clé-valeur, les délégués (style Cocoa) et le modèle d'action cible. Les exigences de liaison tardives rendent très difficile l'implémentation de l'API Cocoa dans un langage typé lié à la compilation comme C ++ ⁱ. Vous pouvez, bien sûr, écrire une application C ++ pure qui s'exécute sur OS X. Elle ne peut tout simplement pas utiliser les API Cocoa.

Ainsi, vous avez deux options si vous souhaitez partager du code entre des applications C ++ sur d'autres plates-formes et votre application basée sur Cocoa. La première consiste à écrire la couche de modèle en C ++ et l'interface graphique en Cocoa. Il s'agit d'une approche courante utilisée par certaines très grandes applications, y compris Mathematica . Votre code C ++ peut rester inchangé (vous n'avez pas besoin d'extensions Apple "funky" pour écrire ou compiler du C ++ sous OS X). Votre couche de contrôleur utilisera probablement Objective-C ++ (peut-être l'extension Apple "funky" à laquelle vous faites référence). Objective-C ++ est un sur-ensemble de C ++, tout comme Objective-C est un sur-ensemble de C. En Objective-C ++, vous pouvez faire des messages de style objc en passant des appels (comme [some-objc-object callMethod];) à partir d'une fonction C ++. Inversement, vous pouvez appeler des fonctions C ++ à partir du code ObjC comme:

@interface MyClass {
    MyCPPClass *cppInstance;
}
@end

@implementation MyClass
- (id)init {
    if(self = [super init]) {
        cppInstance = new MyCPPClass();
    }
    return self;
}
- (void) dealloc {
    if(cppInstance != NULL) delete cppInstance;
    [super dealloc];
}
- (void)callCpp {
    cppInstance->SomeMethod();
}
@end

Vous pouvez en savoir plus sur Objective-C ++ dans le guide du langage Objective-C . La couche de vue peut alors être pure Objective-C.

La deuxième option consiste à utiliser une boîte à outils C ++ multiplateforme. Le Qtboîte à outils pourrait convenir. Les boîtes à outils multiplateformes sont généralement méprisées par les utilisateurs de Mac car elles n'obtiennent pas tous les détails de l'apparence et de la convivialité et les utilisateurs de Mac s'attendent à ce que l'interface utilisateur des applications Mac soit polie. Cependant, Qt fait un travail étonnamment bon et en fonction du public et de l'utilisation de votre application, cela peut être suffisant. De plus, vous perdrez certaines des technologies spécifiques à OS X telles que Core Animation et certaines fonctionnalités QuickTime, bien qu'il existe des remplacements approximatifs dans l'API Qt. Comme vous le faites remarquer, Carbon ne sera pas porté en 64 bits. Depuis que Qt est implémenté sur les API Carbon, Trolltech / Nokia ont dû porter Qt sur l'API Cocoa pour le rendre compatible 64 bits. Je crois comprendre que la prochaine version de Qt (actuellement en version) complète cette transition et est compatible 64 bits sous OS X. Vous voudrez peut-être jeter un œil à la source de Qt 4.5 si vous êtes intéressé par l'intégration de C ++ et des API Cocoa.


ⁱ Pendant un certain temps, Apple a rendu l'API Cocoa disponible pour Java, mais le pont a nécessité un réglage manuel approfondi et n'a pas été en mesure de gérer les technologies plus avancées telles que les liaisons clé-valeur décrites ci-dessus. Les langages actuellement typés dynamiquement et liés à l'exécution comme Python, Ruby, etc. sont la seule véritable option pour écrire une application Cocoa sans Objective-C (bien que ces ponts utilisent bien sûr Objective-C sous le capot).


J'essaye actuellement de porter ma petite application Ogre3D, cela me semble TRÈS douloureux. Apple essaie-t-il de convertir tout le monde en Objc, ou est-ce vraiment une fonctionnalité?
jokoon

68

Eh bien, cela peut sembler idiot, mais en fait, nous pouvons écrire du code C ++ pur pour créer une interface graphique pour Mac OS X, mais nous devons établir un lien avec le framework Cocoa.

/*
 * test1.cpp
 * This program shows how to access Cocoa GUI from pure C/C++
 * and build a truly functional GUI application (although very simple).
 * 
 * Compile using:
 *   g++ -framework Cocoa -o test1 test1.cpp
 *
 * that will output 'test1' binary.
 */


#include <CoreFoundation/CoreFoundation.h>
#include <objc/objc.h>
#include <objc/objc-runtime.h>
#include <iostream>

extern "C" int NSRunAlertPanel(CFStringRef strTitle, CFStringRef strMsg,
                               CFStringRef strButton1, CFStringRef strButton2, 
                               CFStringRef strButton3, ...);


int main(int argc, char** argv)
{
    id app = NULL;
    id pool = (id)objc_getClass("NSAutoreleasePool");
    if (!pool)
    {
        std::cerr << "Unable to get NSAutoreleasePool!\nAborting\n";
        return -1;
    }
    pool = objc_msgSend(pool, sel_registerName("alloc"));
    if (!pool)
    {
        std::cerr << "Unable to create NSAutoreleasePool...\nAborting...\n";
        return -1;
    }
    pool = objc_msgSend(pool, sel_registerName("init"));

    app = objc_msgSend((id)objc_getClass("NSApplication"),
                       sel_registerName("sharedApplication"));

    NSRunAlertPanel(CFSTR("Testing"),
                    CFSTR("This is a simple test to display NSAlertPanel."),
                    CFSTR("OK"), NULL, NULL);

    objc_msgSend(pool, sel_registerName("release"));
    return 0;
}

17
C'est merveilleux. Existe-t-il des exemples plus compliqués disponibles? Par exemple, ouvrir un NSWindow?
imallett

test1.cpp: Dans la fonction 'int main (int, char **)': test1.cpp: 26: 48: erreur: impossible de convertir 'Class {aka objc_class *}' en 'id {aka objc_object *}' dans l'ID d'initialisation pool = objc_getClass ("NSAutoreleasePool"); ^ test1.cpp: 41: 61: erreur: impossible de convertir 'Class {aka objc_class *}' en 'id {aka objc_object *}' pour l'argument '1' en 'objc_object * objc_msgSend (id, SEL, ...)' sel_registerName ("sharedApplication")); ^
Jichao

6
@Jichao voir la compatibilité de Clang avec les types Objective-C internes - le correctif est simple: remplacer objc_getClasspar(id)objc_getClass
Dmitry Isaev

Comment puis-je utiliser un std :: string pour définir par exemple. le titre du panneau d'alerte? J'ai essayé d'utiliser c_str () et autres mais rien n'a fonctionné ...
mdre

1
Cela ne compile plus sous macOS Catalina
JC Rocamonde

18

Oui, vous pouvez simplement utiliser C ++ (c'est-à-dire l'écrire dans des fichiers * .cpp) et même mélanger C ++ et Objective-C dans des fichiers * .mm (le code Objective-C standard est stocké dans des fichiers * .m).

Bien sûr, vous devez toujours utiliser Objective-C pour votre interface utilisateur et créer des wrappers Objective-C pour vos objets C ++. Une autre option consiste à passer à Qt qui est un Framework C ++ prenant en charge Windows, Mac OS X et Linux - et sera publié sous LGPL avec la prochaine version 4.5.


23
Notez que si vous utilisez Qt, votre application sera nul. Les applications basées sur Qt ne ressemblent pas aux applications Mac natives. (Pour un exemple, voir Google Earth.)
Peter Hosey

15
Peter: Ce n'est pas du tout vrai. Les applications basées sur Qt peuvent sembler et se sentir identiques aux applications Mac natives, il vous suffit de faire des ajustements par plate-forme, ce qui est beaucoup plus facile que d'écrire une interface graphique native sur chaque plate-forme.
Mike McQuaid

12
Mike, vous êtes mal informé. Parmi leurs autres défauts, les applications basées sur Qt sur le mac n'utilisent pas du tout les contrôles natifs et la bibliothèque Qt fait tout le dessin elle-même. Cela signifie que les applications Qt n'obtiennent aucune accélération matérielle pour le rendu 2D, elles ne restent pas synchronisées avec les modifications de l'interface utilisateur qu'Apple apporte aux contrôles standard, et une application Qt ne peut pas fournir la conformité ADA ou la scriptabilité à moins que vous ne les réinventiez. roues vous-même. En d'autres termes, N'ESSAYEZ PAS d'envoyer une application Qt sur le Mac. Google peut s'en tirer: vous ne pouvez pas.
NSResponder

13
Ils utilisent les contrôles natifs, c'est pourquoi Qt a une version Cocoa et Carbon. Il a d'autres problèmes, mais beaucoup de gens expédient des applications Qt sur Mac et elles fonctionnent bien (et parfaitement avec un peu de peaufinage).
Mike McQuaid

2
Tout en utilisant de contrôle natif ne signifie pas qu'il va regarder et se sentir comme des applications natives. Ce qui fait une impression native, c'est la différence de chaque système d'exploitation. Si vous réglez votre application pour qu'elle soit ressentie sur une plateforme spécifique, elle ne sera pas ressentie comme native sur une autre plateforme. Et le réglage fin des petits comportements sur une couche une fois abstraite est toujours plus difficile que de le faire sur une couche native.
eonil

9

Oui, vous pouvez les mélanger.

Vous devez utiliser Objective-C pour opérer directement sur vos objets GUI et recevoir des notifications de leur part.

Ces objets Objective-C peuvent appeler directement la logique C ++ si vous les placez dans des fichiers .mm, au lieu des fichiers .m Objective-C purs. Notez que vous pouvez voir des conseils (beaucoup) plus anciens suggérant d'utiliser un .M majuscule pour indiquer Objective-C ++, mais cela est très floconneux et risque de vous embrouiller ainsi que le compilateur.

Vous n'avez pas besoin d'encapsuler chaque objet C ++, mais votre code Objective-C devra contenir des pointeurs vers eux.

Apple ne publie plus d'exemples montrant comment procéder.

Il y a une superbe vidéo de Peter Steinberger hébergée au Realm [Objectif] C ++: Qu'est-ce qui pourrait mal tourner? Je recommande vivement à tous ceux qui utilisent encore Objective-C ++ et vous pouvez rapidement parcourir la transcription.


@SteveS votre lien est également rompu
fferri

@fferi - Le lien Steinberger ci-dessus est corrigé. L'intégration de Carbon Cocoa date de 2007 de developer.apple.com, Apple l'a supprimée. Cela indique que vous ne devriez VRAIMENT pas écrire de nouveau code en utilisant les API Carbon. À ce stade, même maintenir le code existant à l'aide de Carbon est risqué. Reportez-vous à la réponse acceptée pour cette question, ou celle-ci si vous avez besoin de mélanger C ++ / Objective C, mais vous ne devriez pas utiliser Carbon. Cela dit, ici: Carbon-Cocoa-Integration
SteveS

4

Si vous cherchez simplement à utiliser du C ++ pur et simple, cela est absolument pris en charge et vraiment pas différent de toute autre plateforme. Xcode a même un modèle pour cela sous Fichier> Nouveau projet> Utilitaire de ligne de commande> Outil C ++. En outre, un certain nombre de bibliothèques open-source populaires (libcurl, libxml2, sqlite, etc.) sont fournies avec OS X et sont disponibles pour la liaison dynamique. Vous n'êtes pas obligé d'utiliser Cocoa ou quelque chose de spécifique à Apple si vous ne le souhaitez pas.

Si vous souhaitez utiliser Cocoa dans certaines parties de votre application, jetez un œil à Objective-C ++ . Vous pouvez mélanger C ++ et Objective-C dans le même fichier en lui donnant une extension de .mm, ou en cliquant avec le bouton droit sur le fichier dans Xcode et en sélectionnant Obtenir des informations> Général, puis en changeant le type de fichier en sourcecode.cpp.objcpp. La deuxième option est utile si vous avez un fichier .cpp dans lequel vous souhaitez utiliser Objective-C dans un #ifdef spécifique à Mac.


1
BTW, le modèle C ++ (vraiment utile) est parti avec les versions récentes de Xcode (4.x et 5.x)
Jay

1

Bien que ce soit une question vieille de plusieurs années ...

J'ai essayé de créer un wrapper C ++ de certaines classes Cocoa .

C'était une expérience plutôt agréable. C ++ a fourni une meilleure sécurité de type que Objective-C, et m'a fait écrire moins de code. Mais le temps de compilation et la sécurité de la mémoire sont pires. C'est possible, mais certaines fonctionnalités dynamiques n'étaient pas faciles à gérer. Je pense que cela n'a pas de sens de le traiter en C ++.

Quoi qu'il en soit, mon projet a finalement été abandonné en raison de l'annonce de Swift. Il a effacé toutes les raisons pour lesquelles je voulais utiliser C ++ au début, et fournit encore plus et mieux.


0

Si vous écrivez une application purement graphique, c'est-à-dire que vous dessinez tout en utilisant du code, pensez à openFrameworks . C'est un langage de programmation graphique open source construit sur C / C ++. Il a des addons qui permettent aux gens d'étendre la langue. Ils ont un addon pour l'iphone . Je crois qu'il est livré avec la bibliothèque et les projets XCode qui vous aideront à compiler des applications pour iPhone et iPod touch.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.