Использовать C ++ с какао вместо Objective-C?

122

Я хотел бы писать приложения, использующие C ++ и фреймворки Cocoa, потому что Apple не поддерживает 64-разрядную версию Carbon. С ++ кажется довольно ванильным в своей реализации в Linux и Windows, но в Mac OS X кажется, что требуются дополнительные части кода, специфичные для Apple (например, оболочка Obj-C). Также кажется, что Apple заставляет разработчиков писать на Objective-C, а не на C ++, хотя я могу ошибаться.

Я пытаюсь найти способ написать код на Mac, который легко поддерживать кросс-платформенный. Было бы очень неэффективно писать код на C ++ для Linux / Windows, а затем переписывать большие части на Objective-C.

Есть ли способ написать код на C ++, который будет поддерживаться в будущем и поддерживаться в Xcode? Кроме того, если это возможно, как мне смешать C ++ и Objective-C в Xcode? Спасибо.

Брок Вульф
источник

Ответы:

110

Вы не можете полностью написать приложение Какао на C ++. Какао в значительной степени полагается на возможности позднего связывания Objective-C для многих своих основных технологий, таких как привязки значения ключа, делегаты (стиль какао) и шаблон целевого действия. Требования позднего связывания очень затрудняют реализацию Cocoa API на типизированном языке с привязкой ко времени компиляции, например C ++ ⁱ. Вы, конечно, можете написать приложение на чистом C ++, работающее на OS X. Оно просто не может использовать API Какао.

Итак, у вас есть два варианта, если вы хотите поделиться кодом между приложениями C ++ на других платформах и вашим приложением на основе Какао. Первый - написать уровень модели на C ++ и графический интерфейс в Какао. Это общий подход, используемый некоторыми очень большими приложениями, включая Mathematica . Ваш код C ++ можно оставить без изменений (вам не нужны «фанковые» расширения Apple для написания или компиляции C ++ в OS X). Уровень вашего контроллера, скорее всего, будет использовать Objective-C ++ (возможно, «фанковое» расширение Apple, о котором вы говорите). Objective-C ++ - это надмножество C ++, точно так же, как Objective-C - надмножество C. В Objective-C ++ вы можете выполнять вызовы передачи сообщений в стиле objc (например, [some-objc-object callMethod];) из функции C ++. И наоборот, вы можете вызывать функции C ++ из кода ObjC, например:

@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

Вы можете узнать больше об Objective-C ++ в руководстве по языку Objective-C . Тогда слой представления может быть чистым Objective-C.

Второй вариант - использовать кросс-платформенный инструментарий C ++. Qtнабор инструментов может соответствовать всем требованиям. Кросс-платформенные инструменты обычно презираются пользователями Mac, потому что они не получают все детали внешнего вида в точности, а пользователи Mac ожидают совершенства в пользовательском интерфейсе приложений Mac. Однако Qt работает на удивление хорошо, и в зависимости от аудитории и использования вашего приложения может быть достаточно хорошим. Вдобавок вы потеряете некоторые специфические для OS X технологии, такие как Core Animation и некоторые функции QuickTime, хотя в Qt API есть приблизительные замены. Как вы указываете, Carbon не будет перенесен на 64-разрядную версию. Поскольку Qt реализован на Carbon API, Trolltech / Nokia пришлось перенести Qt на Cocoa API, чтобы сделать его 64-битным. Насколько я понимаю, следующая версия Qt (в настоящее время в выпуске кандидат) завершает этот переход и является 64-битной совместимой с OS X. Возможно, вы захотите взглянуть на исходный код Qt 4.5, если вы заинтересованы в интеграции C ++ и API Cocoa.


ⁱ Некоторое время Apple сделала Cocoa API доступным для Java, но мост требовал обширной ручной настройки и был неспособен обрабатывать более продвинутые технологии, такие как привязки значений ключей, описанные выше. В настоящее время динамически типизированные языки с привязкой к среде выполнения, такие как Python, Ruby и т. Д., Являются единственным реальным вариантом для написания приложения Какао без Objective-C (хотя, конечно, эти мосты используют Objective-C под капотом).

Барри Уорк
источник
Сейчас я пытаюсь перенести свое небольшое приложение Ogre3D, это кажется ОЧЕНЬ болезненным. Apple пытается преобразовать всех в Objc, или это действительно особенность?
jokoon
68

Что ж, это может показаться глупым, но на самом деле мы можем написать чистый код C ++ для создания графического интерфейса для Mac OS X, но мы должны связать его с фреймворком 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. Дж. Ади Лима
источник
17
Это замечательно. Есть ли более сложные примеры? Например, открывая NSWindow?
imallett 01
test1.cpp: в функции 'int main (int, char **)': test1.cpp: 26: 48: ошибка: невозможно преобразовать 'Class {aka objc_class *}' в 'id {aka objc_object *}' в идентификаторе инициализации пул = objc_getClass ("NSAutoreleasePool"); ^ test1.cpp: 41: 61: ошибка: невозможно преобразовать 'Class {aka objc_class *}' в 'id {aka objc_object *}' для аргумента '1' в 'objc_object * objc_msgSend (id, SEL, ...)' sel_registerName ( "sharedApplication")); ^
Jichao
6
@Jichao см. Совместимость Clang с внутренними типами Objective-C - исправление простое: заменить objc_getClassна(id)objc_getClass
Дмитрий Исаев
Как я могу использовать std :: string для установки, например. заголовок для панели предупреждений? Я пробовал использовать c_str () и ему подобные, но ничего не
помогло
2
Это больше не компилируется в macOS Catalina
JC Rocamonde
18

Да, вы можете просто использовать C ++ (т.е. записывать его в файлы * .cpp) и даже смешивать C ++ и Objective-C внутри файлов * .mm (стандартный код Objective-C хранится в файлах * .m).

Конечно, вам все равно придется использовать Objective-C для своего пользовательского интерфейса и создавать оболочки Objective-C для ваших объектов C ++. Другой вариант - перейти на Qt, который представляет собой C ++ Framework, поддерживающий Windows, Mac OS X и Linux, и будет выпущен под LGPL со следующей версией 4.5.

FHE
источник
23
Обратите внимание, что если вы используете Qt, ваше приложение будет отстойным. Приложения на основе Qt не похожи на родные приложения Mac. (Например, см. Google Планета Земля.)
Питер Хози,
15
Питер: Это совсем не так. Приложения на основе Qt могут выглядеть и ощущаться идентично родным приложениям Mac, вам просто нужно выполнить настройку для каждой платформы, что намного проще, чем писать собственный графический интерфейс на каждой платформе.
Майк Маккуэйд,
12
Майк, ты дезинформирован. Среди других недостатков, приложения на основе Qt на Mac вообще не используют собственные элементы управления, а библиотека Qt сама выполняет все рисование. Это означает, что приложения Qt не получают никакого аппаратного ускорения для 2D-рендеринга, они не синхронизируются с изменениями пользовательского интерфейса, которые Apple вносит в стандартные элементы управления, а приложение Qt не может обеспечить соответствие ADA или возможность создания сценариев, если вы не изобретете их заново. колеса сами. Другими словами, НЕ ПЫТАЙТЕСЬ отправить приложение Qt на Mac. Google может сойти с рук: вы не можете.
NSResponder 01
13
Они используют собственные элементы управления, поэтому у Qt есть версии Cocoa и Carbon. У него есть другие проблемы, но многие люди отправляют приложения Qt на Mac, и они работают нормально (и отлично с небольшой настройкой).
Майк Маккуэйд
2
Только с помощью нативного контроля не означает , что она будет выглядеть и чувствовать себя как родные приложения. Что делает родное ощущение, так это различие каждой ОС. Если вы настроите свое приложение на определенную платформу, оно не будет ощущаться как родное на другой платформе. И тонкая настройка небольшого поведения на однажды абстрактном уровне всегда сложнее, чем на собственном уровне.
eonil
9

Да, вы можете их смешивать.

Вам необходимо использовать Objective-C, чтобы напрямую работать с объектами графического интерфейса и получать от них уведомления.

Эти объекты Objective-C могут напрямую вызывать логику C ++, если вы помещаете их в файлы .mm вместо чистых файлов .m Objective-C. Обратите внимание, что вы можете увидеть (гораздо) более старые советы, предлагающие использовать верхний регистр .M для обозначения Objective-C ++, но это очень нестабильно и может запутать вас, а также компилятор.

Вам не нужно оборачивать каждый объект C ++, но ваш код Objective-C должен содержать указатели на них.

Apple больше не публикует образцы, показывающие, как это сделать.

Есть отличное видео Питера Штайнбергера, размещенное на Realm [Objective] C ++: Что могло пойти не так? Я настоятельно рекомендую всем, кто все еще использует Objective-C ++, и вы можете быстро просмотреть стенограмму.

Энди Дент
источник
@SteveS, твоя ссылка тоже не работает
fferri
@fferi - ссылка на Steinberger выше исправлена. Carbon Cocoa Integration была с 2007 года с сайта developer.apple.com, Apple удалила ее. Это означает, что вам ДЕЙСТВИТЕЛЬНО не следует писать новый код с использованием API-интерфейсов Carbon. На этом этапе даже поддерживать существующий код с использованием Carbon рискованно. Обратитесь к принятому ответу на этот вопрос или к этому, если вам нужно смешать C ++ / Objective C, но вы не должны использовать Carbon. Тем не менее, здесь: Углерод-какао-интеграция
SteveS
4

Если вы просто хотите использовать простой ванильный C ++, он абсолютно поддерживается и ничем не отличается от любой другой платформы. В Xcode даже есть шаблон для этого в меню «Файл»> «Новый проект»> «Утилита командной строки»> «Инструмент C ++». Кроме того, ряд популярных библиотек с открытым исходным кодом (libcurl, libxml2, sqlite и т.д.) поставляется с OS X и доступен для динамической компоновки. Вам не обязательно использовать Какао или что-то специфическое для Apple, если вы этого не хотите.

Если вы действительно хотите использовать Какао в определенных частях вашего приложения, взгляните на Objective-C ++ . Вы можете смешивать C ++ и Objective-C в одном файле, задав ему расширение .mm или щелкнув правой кнопкой мыши файл в Xcode и выбрав Get Info> General, а затем изменив тип файла на sourcecode.cpp.objcpp. Второй вариант полезен, если у вас есть файл .cpp, в котором вы хотите использовать Objective-C в рамках специфичного для Mac #ifdef.

Мэтт Стивенс
источник
1
Кстати, (действительно полезный) шаблон C ++ ушел с последними версиями Xcode (4.x и 5.x)
Джей
1

Хотя это многолетний вопрос ...

Я попытался сделать C ++ оболочку некоторых классов Какао .

Это был довольно приятный опыт. C ++ обеспечил лучшую безопасность типов, чем Objective-C, и заставил меня писать меньше кода. Но время компиляции и безопасность памяти хуже. Это возможно, но с некоторыми динамическими функциями было нелегко справиться. Думаю, на C ++ нет смысла заниматься этим.

В любом случае мой проект был окончательно заброшен из-за анонса Swift. Он устранил все причины, по которым я хотел сначала использовать C ++, и предоставляет еще больше и лучше.

eonil
источник
0

Если вы пишете чисто графическое приложение, т. Е. Все рисуете с помощью кода, рассмотрите openFrameworks . Это графический язык программирования с открытым исходным кодом, созданный на основе C / C ++. У него есть надстройки, которые позволяют людям расширять язык. У них есть аддон для iphone . Я считаю, что он поставляется с библиотекой и проектами XCode, которые помогут вам компилировать приложения для iPhone и iPod touch.

milesmeow
источник