Używać C ++ z kakao zamiast Objective-C?

122

Chciałbym pisać aplikacje, które używają C ++ i frameworków Cocoa, ponieważ Apple nie obsługuje 64-bitowej wersji Carbon. C ++ wydaje się być dość waniliowy w swojej implementacji w Linuksie i Windowsie, ale w Mac OS X wydaje się, że wymagane są dodatkowe specyficzne dla Apple fragmenty kodu (takie jak opakowanie Obj-C). Wygląda również na to, że Apple zmusza programistów do pisania w Objective-C, a nie w C ++, chociaż mogę się mylić.

Próbuję znaleźć ścieżkę do pisania kodu na Macu, która byłaby łatwa do utrzymania na wielu platformach. Konieczność pisania kodu w C ++ dla Linux / Windows, a następnie przepisywania dużych fragmentów w Objective-C byłaby bardzo nieefektywna.

Czy istnieje sposób na napisanie kodu w C ++, który będzie obsługiwany w przyszłości i obsługiwany w Xcode? Ponadto, jeśli jest to możliwe, jak mieszać C ++ i Objective-C w Xcode? Dzięki.

Brock Woolf
źródło

Odpowiedzi:

110

Nie można napisać aplikacji Cocoa w całości w języku C ++. Cocoa w dużym stopniu opiera się na późnych możliwościach wiązania Objective-C w przypadku wielu podstawowych technologii, takich jak powiązania klucz-wartość, delegaci (styl kakaowy) i wzorzec działania docelowego. Wymagania dotyczące późnego wiązania bardzo utrudniają implementację interfejsu API Cocoa w języku typizowanym związanym z czasem kompilacji, takim jak C ++ ⁱ. Możesz oczywiście napisać aplikację w czystym języku C ++ działającą na systemie OS X. Po prostu nie może ona korzystać z API Cocoa.

Masz więc dwie opcje, jeśli chcesz udostępniać kod między aplikacjami C ++ na innych platformach i aplikacją opartą na kakao. Pierwszym jest napisanie warstwy modelu w C ++ i GUI w Cocoa. Jest to typowe podejście stosowane przez niektóre bardzo duże aplikacje, w tym Mathematica . Twój kod C ++ może pozostać niezmieniony (nie potrzebujesz "funky" rozszerzeń Apple, aby pisać lub kompilować C ++ na OS X). Twoja warstwa kontrolera prawdopodobnie będzie korzystać z Objective-C ++ (być może "funky" rozszerzenia Apple, o którym mówisz). Objective-C ++ jest nadzbiorem C ++, tak jak Objective-C jest nadzbiorem C. W Objective-C ++, można tworzyć komunikaty w stylu objc, przekazujące wywołania (na przykład [some-objc-object callMethod];) z poziomu funkcji C ++. I odwrotnie, możesz wywoływać funkcje C ++ z poziomu kodu ObjC, na przykład:

@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

Możesz dowiedzieć się więcej o Objective-C ++ w przewodniku po języku Objective-C . Warstwa widoku może wtedy być czystą Objective-C.

Drugą opcją jest użycie wieloplatformowego zestawu narzędzi C ++. Plik Qtzestaw narzędzi może pasować do rachunku. Wieloplatformowe zestawy narzędzi są generalnie pogardzane przez użytkowników komputerów Mac, ponieważ nie zapewniają one wszystkich szczegółów wyglądu i dotyku, a użytkownicy komputerów Mac oczekują dopracowania w interfejsie aplikacji na komputery Mac. Qt wykonuje jednak zaskakująco dobrą robotę i w zależności od odbiorców i sposobu użytkowania aplikacji może być wystarczająco dobry. Ponadto stracisz na niektórych technologiach specyficznych dla OS X, takich jak Core Animation i niektóre funkcje QuickTime, chociaż istnieją przybliżone zamienniki w Qt API. Jak zauważyłeś, Carbon nie zostanie przeniesiony do wersji 64-bitowej. Ponieważ Qt jest zaimplementowany w Carbon API, Trolltech / Nokia musiało przenieść Qt do Cocoa API, aby było kompatybilne z 64-bitowym. Rozumiem, że następne wydanie Qt (obecnie kandydat do wydania) kończy to przejście i jest kompatybilny z 64-bitowym systemem OS X. Możesz rzucić okiem na źródło Qt 4.5, jeśli jesteś zainteresowany integracją C ++ i API Cocoa.


ⁱ Przez jakiś czas Apple udostępniło API Cocoa dla Javy, ale most wymagał obszernego dostrajania ręcznego i nie był w stanie obsłużyć bardziej zaawansowanych technologii, takich jak opisane powyżej wiązania klucz-wartość. Obecnie dynamicznie wpisywane języki związane ze środowiskiem uruchomieniowym, takie jak Python, Ruby itp., Są jedyną realną opcją pisania aplikacji Cocoa bez Objective-C (chociaż oczywiście te mosty używają Objective-C pod maską).

Barry Wark
źródło
Obecnie próbuję przenieść moją małą aplikację Ogre3D, wydaje się to BARDZO bolesne. Czy Apple próbuje przekonwertować wszystkich na Objc, czy to naprawdę funkcja?
żart,
68

Cóż, może to zabrzmieć głupio, ale tak naprawdę możemy napisać czysty kod C ++, aby stworzyć GUI dla Mac OS X, ale musimy połączyć się z frameworkiem 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;
}
FX. J. Adi Lima
źródło
17
To jest cudowne. Czy są dostępne bardziej skomplikowane przykłady? Na przykład, otwierając NSWindow?
imallett
test1.cpp: W funkcji „int main (int, char **)”: test1.cpp: 26: 48: error: nie można przekonwertować „Class {aka objc_class *}” na „id {aka objc_object *}” w identyfikatorze inicjalizacji pool = objc_getClass ("NSAutoreleasePool"); ^ test1.cpp: 41: 61: błąd: nie można przekonwertować „Class {aka objc_class *}” na „id {aka objc_object *}” dla argumentu „1” na „objc_object * objc_msgSend (id, SEL, ...)” sel_registerName ("sharedApplication")); ^
Jichao,
6
@Jichao zobaczyć kompatybilność dzyń z wewnętrznych typów Objective-C - poprawka jest prosta: wymienić objc_getClassz(id)objc_getClass
Dmitrij Isajew
Jak mogę użyć std :: string, aby ustawić np. tytuł panelu alertów? Próbowałem użyć c_str () i podobnych, ale nic nie działało ...
mdre
2
To już się nie kompiluje w macOS Catalina
JC Rocamonde
18

Tak, możesz po prostu użyć C ++ (tj. Zapisać go w plikach * .cpp), a nawet mieszać C ++ i Objective-C w plikach * .mm (standardowy kod Objective-C jest przechowywany w plikach * .m).

Oczywiście nadal musisz używać Objective-C jako interfejsu użytkownika i tworzyć opakowania Objective-C dla swoich obiektów C ++. Inną opcją jest przejście na Qt, który jest platformą C ++, która obsługuje systemy Windows, Mac OS X i Linux - i zostanie wydana na licencji LGPL wraz z następną wersją 4.5.

fhe
źródło
23
Pamiętaj, że jeśli używasz Qt, Twoja aplikacja będzie do niczego. Aplikacje oparte na Qt nie wyglądają i nie przypominają natywnych aplikacji Mac. (Na przykład zobacz Google Earth.)
Peter Hosey,
15
Peter: To wcale nie jest prawda. Aplikacje oparte na Qt mogą wyglądać i czuć się identycznie jak natywne aplikacje na Maca, wystarczy je dostosować do platformy, co jest znacznie łatwiejsze niż pisanie natywnego GUI na każdej platformie.
Mike McQuaid
12
Mike, jesteś źle poinformowany. Wśród innych niedociągnięć aplikacje oparte na Qt na komputery Mac w ogóle nie używają natywnych formantów, a biblioteka Qt sama wykonuje rysowanie. Oznacza to, że aplikacje Qt nie uzyskują żadnej akceleracji sprzętowej dla renderowania 2D, nie pozostają zsynchronizowane ze zmianami interfejsu użytkownika, które Apple wprowadza do standardowych elementów sterujących, a aplikacja Qt nie może zapewnić zgodności z ADA ani możliwości skryptowania, chyba że wymyślisz je na nowo jeździ sam. Innymi słowy, NIE PRÓBUJ wysyłać aplikacji Qt na komputer Mac. Google może uciec: nie możesz.
NSResponder
13
Używają natywnych elementów sterujących, dlatego Qt ma wersję Cocoa i Carbon. Ma inne problemy, ale wiele osób wysyła aplikacje Qt na Maca i działają one dobrze (i doskonale z odrobiną poprawek).
Mike McQuaid
2
Tylko przy użyciu natywnego kontroli nie oznacza to będzie wyglądać i czuć się jak natywne aplikacje. To, co tworzy natywne wrażenie, to różnica w każdym systemie operacyjnym. Jeśli dostroisz swoją aplikację tak, aby działała na określonej platformie, nie będzie ona natywna na innej platformie. A dopracowanie małych zachowań na raz wyabstrahowanej warstwie jest zawsze trudniejsze niż robienie tego na warstwie natywnej.
eonil
9

Tak, możesz je mieszać.

Musisz użyć Objective-C, aby bezpośrednio operować na obiektach GUI i otrzymywać od nich powiadomienia.

Te obiekty Objective-C mogą bezpośrednio wywoływać logikę C ++, jeśli umieścisz je w plikach .mm, zamiast czystych plików .m Objective-C. Zauważ, że możesz zobaczyć (dużo) starsze porady sugerujące użycie dużych liter .M do wskazania Objective-C ++, ale jest to bardzo niestabilne i może zmylić Ciebie i kompilator.

Nie musisz zawijać każdego obiektu C ++, ale Twój kod Objective-C będzie musiał zawierać wskaźniki do nich.

Apple nie publikuje już żadnych próbek pokazujących, jak to zrobić.

W Realm [Objective] C ++: What Could Possably Go Wrong? Gorąco polecam każdemu, kto nadal używa Objective-C ++ i możesz szybko przejrzeć transkrypcję.

Andy Dent
źródło
@SteveS Twój link też jest uszkodzony
fferri
@fferi - powyższy link Steinberger został naprawiony. Integracja Carbon Cocoa pochodzi z 2007 roku z developer.apple.com, Apple ją usunęła. Oznacza to, że NAPRAWDĘ nie powinieneś pisać nowego kodu za pomocą Carbon API. W tym momencie nawet utrzymanie istniejącego kodu za pomocą Carbon jest ryzykowne. Zapoznaj się z zaakceptowaną odpowiedzią na to pytanie lub to, jeśli chcesz mieszać C ++ / Objective C, ale nie powinieneś używać Carbon. To powiedziawszy, tutaj: Integracja węgla i kakao
SteveS
4

Jeśli chcesz używać zwykłego, waniliowego C ++, jest to absolutnie obsługiwane i nie różni się niczym od innych platform. Xcode ma nawet szablon dla niego w menu Plik> Nowy projekt> Narzędzie wiersza poleceń> Narzędzie C ++. Ponadto wiele popularnych bibliotek open source (libcurl, libxml2, sqlite itp.) Jest dostarczanych z systemem OS X i jest dostępnych do dynamicznego łączenia. Nie musisz używać kakao ani niczego specyficznego dla Apple, jeśli nie chcesz.

Jeśli chcesz używać Cocoa w niektórych częściach swojej aplikacji, spójrz na Objective-C ++ . Możesz mieszać C ++ i Objective-C w tym samym pliku, nadając mu rozszerzenie .mm lub klikając prawym przyciskiem myszy plik w Xcode i wybierając Uzyskaj informacje> Ogólne, a następnie zmieniając typ pliku na sourcecode.cpp.objcpp. Druga opcja jest przydatna, jeśli masz plik .cpp, w którym chcesz użyć Objective-C w #ifdef specyficznym dla Maca.

Matt Stevens
źródło
1
BTW, (naprawdę przydatny) szablon C ++ zniknął z ostatnich wersji Xcode (4.x i 5.x)
Jay
1

Chociaż to jest pytanie od lat ...

Ja postarałem się zrobić c ++ wrapper niektórych klas kakao .

To było całkiem miłe doświadczenie. C ++ zapewnia lepsze bezpieczeństwo typów niż Objective-C i zmusza mnie do pisania mniej kodu. Ale czas kompilacji i bezpieczeństwo pamięci są gorsze. Jest to możliwe, ale niektóre funkcje oparte na dynamice nie były łatwe w obsłudze. Myślę, że nie ma sensu zajmować się tym w C ++.

W każdym razie mój projekt został ostatecznie porzucony z powodu ogłoszenia Swift. Wyjaśniło wszystkie powody, dla których chciałem na początku używać C ++ i zapewnia jeszcze więcej i lepiej.

eonil
źródło
0

Jeśli piszesz czysto graficzną aplikację, tzn . Rysujesz wszystko za pomocą kodu, rozważ openFrameworks . Jest to graficzny język programowania typu open source oparty na C / C ++. Posiada dodatki, które pozwalają ludziom na rozszerzenie języka. Mają dodatek do iPhone'a . Wierzę, że jest dostarczany z biblioteką i projektami XCode, które pomogą Ci skompilować aplikacje na iPhone'a i iPoda touch.

milesmeow
źródło