Usa C ++ con Cocoa invece di Objective-C?


122

Vorrei scrivere applicazioni che utilizzano C ++ e il framework Cocoa perché Apple non sta rendendo compatibile Carbon 64-bit. Il C ++ sembra essere piuttosto vaniglia nella sua implementazione su Linux e Windows, ma su Mac OS X sembra che siano necessari ulteriori pezzi di codice specifici per Apple (come un wrapper Obj-C). Sembra anche che Apple stia costringendo gli sviluppatori a scrivere in Objective-C piuttosto che in C ++, anche se potrei sbagliarmi.

Sto cercando di trovare un percorso per scrivere codice sul Mac che sarebbe facile da mantenere multipiattaforma. Dover scrivere codice in C ++ per Linux / Windows e poi riscrivere grandi porzioni in Objective-C sarebbe molto inefficiente.

C'è un modo per scrivere codice in C ++ che sarà supportato per il futuro e supportato in Xcode? Inoltre, se questo è possibile, come potrei mescolare C ++ e Objective-C in Xcode? Grazie.

Risposte:


110

Non è possibile scrivere un'applicazione Cocoa interamente in C ++. Cocoa fa molto affidamento sulle capacità di associazione tardiva di Objective-C per molte delle sue tecnologie principali come le associazioni di valori chiave, i delegati (stile Cocoa) e il modello di azione di destinazione. I requisiti di associazione tardiva rendono molto difficile implementare l'API Cocoa in un linguaggio tipizzato vincolato in fase di compilazione come C ++ ⁱ. Ovviamente puoi scrivere un'app C ++ pura che gira su OS X. Non può usare le API Cocoa.

Quindi, hai due opzioni se desideri condividere il codice tra le app C ++ su altre piattaforme e la tua applicazione basata su Cocoa. Il primo è scrivere il livello del modello in C ++ e la GUI in Cocoa. Questo è un approccio comune utilizzato da alcune app di grandi dimensioni, tra cui Mathematica . Il tuo codice C ++ può essere lasciato invariato (non hai bisogno di estensioni Apple "funky" per scrivere o compilare C ++ su OS X). Il livello del tuo controller probabilmente farà uso di Objective-C ++ (forse l'estensione "funky" di Apple a cui ti riferisci). Objective-C ++ è un superset di C ++, proprio come Objective-C è un superset di C. In Objective-C ++, puoi effettuare chiamate di passaggio di messaggi in stile objc (come [some-objc-object callMethod];) dall'interno di una funzione C ++. Al contrario, puoi chiamare funzioni C ++ dall'interno del codice ObjC come:

@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

Puoi trovare ulteriori informazioni su Objective-C ++ nella guida al linguaggio Objective-C . Il livello di visualizzazione può quindi essere puro Objective-C.

La seconda opzione è utilizzare un toolkit C ++ multipiattaforma. Il Qtil toolkit potrebbe adattarsi al conto. I toolkit multipiattaforma sono generalmente disprezzati dagli utenti Mac perché non ottengono tutti i dettagli dell'aspetto e delle funzionalità esattamente giusti e gli utenti Mac si aspettano un tocco di lucentezza nell'interfaccia utente delle applicazioni Mac. Qt fa un lavoro sorprendentemente buono, tuttavia, e a seconda del pubblico e dell'uso della tua app, potrebbe essere abbastanza buono. Inoltre, perderai alcune delle tecnologie specifiche di OS X come Core Animation e alcune funzionalità QuickTime, sebbene ci siano sostituzioni approssimative nell'API Qt. Come fai notare, Carbon non sarà portato a 64 bit. Poiché Qt è implementato sulle API Carbon, Trolltech / Nokia ha dovuto portare Qt all'API Cocoa per renderlo compatibile a 64 bit. La mia comprensione è che la prossima versione di Qt (attualmente in rilascio candiate) completa questa transizione ed è compatibile a 64 bit su OS X. Potresti voler dare un'occhiata ai sorgenti di Qt 4.5 se sei interessato a integrare C ++ e le API Cocoa.


ⁱ Per un po 'di tempo Apple ha reso disponibile l'API Cocoa per Java, ma il bridge ha richiesto un'estesa messa a punto manuale e non è stata in grado di gestire le tecnologie più avanzate come le associazioni valore-chiave descritte sopra. Attualmente, linguaggi runtime-bound tipizzati dinamicamente come Python, Ruby, ecc. Sono l'unica vera opzione per scrivere un'app Cocoa senza Objective-C (sebbene ovviamente questi bridge utilizzino Objective-C sotto il cofano).


Attualmente sto provando a portare la mia piccola applicazione Ogre3D, sembra MOLTO doloroso. Apple sta cercando di convertire tutti in Objc o è davvero una funzionalità?
jokoon

68

Bene, può sembrare sciocco, ma in realtà possiamo scrivere codice C ++ puro per creare GUI per Mac OS X, ma dobbiamo collegarci al 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
Questo è meraviglioso. Sono disponibili esempi più complicati? Ad esempio, l'apertura di una NSWindow?
imallett

test1.cpp: nella funzione 'int main (int, char **)': test1.cpp: 26: 48: errore: impossibile convertire "Class {aka objc_class *}" in "id {aka objc_object *}" nell'id di inizializzazione pool = objc_getClass ("NSAutoreleasePool"); ^ test1.cpp: 41: 61: errore: impossibile convertire "Class {aka objc_class *}" in "id {aka objc_object *}" per argomento "1" in "objc_object * objc_msgSend (id, SEL, ...)" sel_registerName ( "sharedApplication")); ^
Jichao,

6
@Jichao vedi la compatibilità di Clang con i tipi Objective-C interni - la correzione è semplice: sostituisci objc_getClasscon(id)objc_getClass
Dmitry Isaev

Come posso usare uno std :: string per impostare ad es. il titolo per il pannello di allerta? Ho provato a usare c_str () e simili ma niente ha funzionato ...
mdre

1
Questo non si compila più in macOS Catalina
JC Rocamonde

18

Sì, puoi semplicemente usare C ++ (cioè scrivendolo in file * .cpp) e persino mescolare C ++ e Objective-C all'interno di file * .mm (il codice Objective-C standard è memorizzato in file * .m).

Ovviamente, devi ancora usare Objective-C per la tua interfaccia utente e creare wrapper Objective-C per i tuoi oggetti C ++. Un'altra opzione è passare a Qt, un framework C ++ che supporta Windows, Mac OS X e Linux e verrà rilasciato sotto LGPL con la prossima versione 4.5.


23
Nota che se usi Qt, la tua app farà schifo. Le app basate su Qt non hanno l'aspetto e la sensazione di app native del Mac. (Per un esempio, vedere Google Earth.)
Peter Hosey

15
Peter: Non è affatto vero. Le app basate su Qt possono sembrare identiche alle app native del Mac, devi solo fare il tweaking per piattaforma, qualcosa che è molto più semplice che scrivere una GUI nativa su ciascuna piattaforma.
Mike McQuaid

12
Mike, sei male informato. Tra le loro altre carenze, le app basate su Qt sul Mac non utilizzano affatto i controlli nativi e la libreria Qt fa tutto il disegno da sola. Ciò significa che le app Qt non ottengono alcuna accelerazione hardware per il rendering 2D, non rimangono sincronizzate con le modifiche dell'interfaccia utente che Apple apporta ai controlli standard e un'app Qt non può fornire conformità ADA o scriptabilità a meno che non vengano reinventate ruote da soli. In altre parole, NON TENTARE di spedire un'app Qt sul Mac. Google può farla franca: tu no.
NSResponder

13
Usano i controlli nativi, ecco perché Qt ha una versione Cocoa e Carbon. Ha altri problemi ma molte persone spediscono applicazioni Qt su Mac e funzionano bene (e perfettamente con un po 'di aggiustamenti).
Mike McQuaid

2
Usando solo di controllo nativo non significa che avrà un aspetto e sentire come applicazioni native. Ciò che rende una sensazione nativa è la differenza di ciascun sistema operativo. Se ottimizzi la tua app in modo che venga percepita in una piattaforma specifica, non verrà percepita come nativa su un'altra piattaforma. E la messa a punto di piccoli comportamenti su un livello una volta astratto è sempre più difficile che farlo su un livello nativo.
eonil

9

Sì, puoi mescolarli.

È necessario utilizzare Objective-C per operare direttamente sugli oggetti della GUI e ricevere notifiche da essi.

Questi oggetti Objective-C possono chiamare direttamente la logica C ++ se vengono inseriti in file .mm, invece dei puri file Objective-C .m. Nota che potresti vedere consigli (molto) più vecchi che suggeriscono di usare un .M maiuscolo per indicare Objective-C ++ ma questo è molto instabile e probabilmente confonderà te e il compilatore.

Non è necessario avvolgere ogni oggetto C ++ ma il codice Objective-C dovrà contenere puntatori a essi.

Apple non pubblica più alcun campione che mostra come farlo.

C'è un ottimo video di Peter Steinberger ospitato da Realm [Objective] C ++: What Could Possibly Go Wrong? Consiglio vivamente a chiunque utilizzi ancora Objective-C ++ e puoi scorrere rapidamente la trascrizione.


@SteveS anche il tuo link è interrotto
fferri

@fferi - Il collegamento Steinberger sopra è stato corretto. Carbon Cocoa Integration era del 2007 da developer.apple.com, Apple lo ha rimosso. Ciò indica che DAVVERO non dovresti scrivere nuovo codice utilizzando le API di Carbon. A questo punto, anche il mantenimento del codice esistente utilizzando Carbon è rischioso. Fai riferimento alla risposta accettata per questa domanda, o questa se hai bisogno di mescolare C ++ / Objective C, ma non dovresti usare Carbon. Detto questo, qui: Carbon-Cocoa-Integration
SteveS

4

Se stai solo cercando di utilizzare C ++ semplice, questo è assolutamente supportato e non è davvero diverso da qualsiasi altra piattaforma. Xcode ha anche un modello per esso in File> Nuovo progetto> Utilità della riga di comando> Strumento C ++. Inoltre, alcune delle popolari librerie open source (libcurl, libxml2, sqlite, ecc.) Vengono fornite con OS X e sono disponibili per il collegamento dinamico. Non devi usare Cocoa o qualcosa di specifico di Apple se non vuoi.

Se vuoi usare Cocoa in alcune parti della tua app, dai un'occhiata a Objective-C ++ . Puoi mescolare C ++ e Objective-C nello stesso file dandogli un'estensione .mm o facendo clic con il pulsante destro del mouse sul file in Xcode e selezionando Ottieni informazioni> Generale, quindi modificando il tipo di file in sourcecode.cpp.objcpp. La seconda opzione è utile se si dispone di un file .cpp in cui si desidera utilizzare Objective-C all'interno di un #ifdef specifico per Mac.


1
A proposito, il modello C ++ (davvero utile) è andato con le versioni recenti di Xcode (4.xe 5.x)
Jay

1

Anche se questa è una domanda vecchia di anni ...

Ho provato a creare wrapper C ++ di alcune classi Cocoa .

È stata una bella esperienza. C ++ ha fornito una migliore sicurezza dei tipi rispetto a Objective-C e mi ha fatto scrivere meno codice. Ma il tempo di compilazione e la sicurezza della memoria sono peggiori. È possibile, ma alcune funzionalità basate sulla dinamica non erano facili da gestire. Penso che non abbia senso affrontarlo in C ++.

Comunque il mio progetto è stato finalmente abbandonato a causa dell'annuncio di Swift. Ha chiarito tutti i motivi per cui volevo usare C ++ all'inizio e ne fornisce ancora di più e meglio.


0

Se stai scrivendo un'applicazione puramente grafica, cioè stai disegnando tutto usando il codice, considera openFrameworks . È un linguaggio di programmazione grafica opensource costruito su C / C ++. Ha componenti aggiuntivi che consentono alle persone di estendere la lingua. Hanno un addon per l'iPhone . Credo che venga fornito con la libreria e i progetti XCode che ti aiuteranno a compilare app per iPhone e iPod touch.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.