Статьи

Использование C и C ++ в приложении для iOS с Objective-C ++

В моем предыдущем уроке я обсуждал, как разрабатывать приложения для Android на C или C ++ с использованием Native Development Kit. В этом уроке я расскажу, как использовать C или C ++ вместе с Objective-C в iOS. В отличие от Android, который нуждается в специальном API (NDK) для поддержки нативной разработки, iOS поддерживает его по умолчанию. Разработка на C или C ++ более проста с iOS благодаря функции под названием Objective-C ++. Я расскажу, что такое Objective-C ++, его ограничения и как он используется для создания приложений для iOS.

Что такое Objective-C ++?

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

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

Несмотря на то, что сейчас Swift является рекомендуемым языком для разработки приложений для iOS, все же есть веские причины использовать более старые языки, такие как C, C ++ и Objective-C. Несмотря на быстрый рост Swift, Objective-C по-прежнему является доминирующим языком на iOS из-за огромного количества существующих приложений и библиотек, уже созданных с его помощью.

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

Использование Objective-C ++

Окончательный проект для этого урока можно найти на GitHub .

Создать проект

Откройте XCode и выберите Создать новый проект XCode .

Экран приветствия

На экране выбора шаблона выберите Single View Application на вкладке iOS-приложения и нажмите Next .

Выберите шаблон

На экране параметров проекта назовите продукт HelloCpp . Введите свою организацию и идентификатор организации в обратном стиле доменного имени.

Варианты проекта

Поскольку это не совсем язык, нет возможности создать проект Objective-C ++. Доступно либо Objective-C, либо Swift. Для этого проекта выберите Objective-C. Оставьте остальные параметры такими, как они есть, нажмите « Далее» и выберите папку для сохранения проекта.

Создать проект

C ++

Время добавить код на C ++. Если вы впервые используете C ++, ознакомьтесь с этим руководством по языку. Посмотрите на панель Project Navigator слева. Большинство файлов заканчиваются на .h или .m . Те, которые заканчиваются на .h, являются заголовочными файлами, в то время как файлы с .m являются исходными файлами Objective-C

Создайте класс C ++, который будет вызываться из файла Objective-C. Создайте новый файл, используя пункт меню Файл -> Создать -> Файл… или нажмите N + N. В открывшемся окне шаблона файла выберите iOS -> Источник -> Файл C ++ и нажмите « Далее» .

Шаблон файла

Назовите файл « Приветствие» , оставьте флажок « Также создать заголовочный файл» и нажмите « Далее» . Сохраните файл в папке HelloCpp .

Параметры файла

Структура проекта теперь должна выглядеть следующим образом. Не стесняйтесь перетаскивать файлы, чтобы улучшить расположение в Project Navigator .

HelloCpp Приветствие

Откройте Greeting.hpp и добавьте следующий код между строками include <stdio.h> и #endif /* Greeting_hpp */ :

 #include <string> class Greeting { std::string greeting; public: Greeting(); std::string greet(); }; 

Определите эти методы в Greeting.cpp , добавив следующий код после строки include "Greeting.hpp" :

 Greeting::Greeting() { greeting = "Hello C++!"; } std::string Greeting::greet() { return greeting; } 

Это простой код, который создает класс с именем Greeting с помощью одного метода с именем greet() который возвращает строковое значение.

Objective-C с C ++

Теперь, когда вы добавили простой класс приветствия C ++, попробуйте вызвать его из Objective-C. Откройте ViewController.m и импортируйте файл заголовка Greeting.hpp :

 #import "ViewController.h" #import "Greeting.hpp" ... 

Объявите переменную типа Greeting внутри блока @interface в ViewController.

 @interface ViewController () { Greeting greeting; } @end 

Показать живые вопросы

Если включен параметр « Показать проблемы в реальном времени » , после добавления предыдущей строки кода сразу же появится сообщение о том, что имя неизвестного типа «Приветствие» . Чтобы устранить эту проблему, переименуйте ViewController.m в ViewController.mm . Это простое соглашение об именах сообщает Xcode, что ViewController хочет смешать Objective-C с C ++. После переименования файла ошибка должна исчезнуть.

Переименовать ViewController

Давайте сделаем приложение более интерактивным, добавив кнопку. Выберите Main.storyboard в Project Navigator, чтобы показать сцену View Controller. Перетащите кнопку из библиотеки объектов в центр представления, как показано ниже. Измените текст на Tap Me! ,

Кнопка Добавить

Создайте розетку UIButton которая указывает на недавно созданную кнопку. Находясь на экране Main.storyboard , откройте Помощник редактора, переключив его с панели инструментов. Нажмите клавишу управления на клавиатуре и перетащите соединитель от кнопки до строки под переменной greeting . Назовите этот выход helloButton .

Кнопка Привет

Откройте ViewController.h и добавьте следующий метод IBAction между @interface и @end :

 - (IBAction)showGreeting; 

Определите этот метод в ViewController.mm с помощью следующего кода, вставленного после функции - (void)didReceiveMemoryWarning и перед @end :

 - (IBAction)showGreeting { NSString* newTitle = [NSString stringWithCString:greeting.greet().c_str() encoding:[NSString defaultCStringEncoding]]; [helloButton setTitle:newTitle forState:UIControlStateNormal]; } 

Этот метод вызывает метод greet() определенный в классе Greeting C ++, и использует возвращаемое строковое значение для замены Tap Me! название кнопки. Подключите кнопку к этому действию, используя ту же технику управления + перетаскивания . Вернитесь к экрану Main.storyboard и откройте Assistant Editor с помощью панели инструментов, затем нажмите и перетащите соединитель с кнопки в - (IBAction)showGreeting метода - (IBAction)showGreeting . Небольшой полый кружок слева от - (IBAction)showGreeting метода - (IBAction)showGreeting должен быть активирован / заполнен, указывая, что Tap Me! Кнопка теперь связана с этим действием.

Показать приветствие

Создайте и запустите приложение. Обратите внимание, что кнопка отображается не в центре симулятора. Исправьте это, включив ограничения Auto Layout, используя технику Control + drag . Подключите кнопку к ее контейнеру и включите вертикальное и горизонтальное центрирование. Запустите приложение еще раз, чтобы увидеть улучшения.

Центральная кнопка

Ограничения

Objective-C ++ на самом деле не объединяет Objective-C с возможностями C ++. То есть классы Objective-C не будут иметь функций, доступных для C ++ и наоборот. Следующие примеры кода иллюстрируют эти ограничения:

Вызов объекта C ++ с использованием синтаксиса Objective C не будет работать

 std::string greet = [greeting greet]; // error 

Конструкторы или деструкторы не могут быть добавлены к объекту Objective C

 @interface ViewController () { Greeting greeting; IBOutlet UIButton *helloButton; ViewController(); // error ~ViewController(); // error } @end 

Ключевые слова this и self не могут использоваться взаимозаменяемо

 std::string greet = self->greeting.greet(); // works std::string greet2 = this->greeting.greet(); // error 

Класс C ++ не может наследоваться от класса Objective C

 #include <stdio.h> #include <string> #include "ViewController.h" class Greeting: public ViewController { // error std::string greeting; public: Greeting(); std::string greet(); }; 

Класс Objective-C не может наследоваться от класса C ++

 #import "Greeting.hpp" @interface Goodbye : Greeting // error @end 

Обработка исключений также не полностью поддерживается при смешивании Objective-C и C ++

Исключение, выброшенное в коде Objective C, не может быть поймано в коде C ++, в то время как исключение, выброшенное в коде C ++, не может быть пойман в коде Objective C.

 double divide(int dividend, int divisor) { if ( divisor == 0 ) { throw "Cannot divide by zero!"; // will not be caught in Objective-C } return (dividend/divisor); } 

Повторное использование библиотек

Возможность многократного использования существующих библиотек C / C ++ является одним из наиболее важных случаев использования нативных языков, и это простой процесс в iOS. В то время как Android все еще требует отдельного NDK, iOS уже поддерживает C и C ++.

SDL

Как и в учебнике по Android NDK , в этом примере мы будем использовать SDL. Simple DirectMedia Layer — это библиотека аппаратных абстракций с открытым исходным кодом, используемая в основном для игр или чего-либо, что связано с высокопроизводительной графикой. Он написан на C, поэтому может быть легко включен в код Objective-C.

Настройка проекта

Сначала загрузите исходный код SDL со страницы загрузки или клонируйте репозиторий Mercurial с помощью:

hg clone http://hg.libsdl.org/SDL

После завершения загрузки или клонирования создайте новый проект приложения единого представления в XCode. Назовите его HelloSDL с языком, установленным в Objective-C.

Вы начнете с нуля, поэтому в Project Navigator выберите следующие выделенные файлы и переместите их в корзину:

Удалить файлы

Удалите следующие ключи из файла Info.plist .

Удалить ключи

Добавьте проект библиотеки SDL в HelloSDL, используя пункт меню Файл -> Добавить файлы в Hello SDL . Перейдите к загруженной или клонированной папке SDL, в Xcode-iOS / SDL / и затем выберите SDL.xcodeproj .

Выберите основной проект HelloSDL в Навигаторе проектов и в разделе «Цели» выберите HelloSDL . Прокрутите вниз до раздела Связанные фреймворки и библиотеки .

Связанные рамки и библиотеки

Нажмите кнопку + , чтобы вручную добавить libSDL2.a и следующие фреймворки:

  • AudioToolbox.framework
  • CoreAudio.framework
  • CoreGraphics.framework
  • CoreMotion.framework
  • Foundation.framework
  • GameController.framework
  • OpenGLES.framework
  • QuartzCore.framework
  • UIKit.framework

Добавить libSDL2.a

Используйте Ctrl + клик, чтобы выбрать несколько фреймворков. Приведите в порядок Навигатор проектов , выбрав недавно добавленные рамки и сгруппировав их с помощью пункта контекстного меню « Новая группа из выбора» .

Добавьте файл main.c в проект. Для этого не нужно создавать файл заголовка, поэтому снимите флажок Также создавать файл заголовка .

Добавить файл C

Мы будем использовать этот пример кода Холмса Футрелла из файла SDL / Xcode-iOS / Template / SDL iOS / main.c :

 /* * rectangles.c * written by Holmes Futrell * use however you want */ #include "SDL.h" #include <time.h> #define SCREEN_WIDTH 320 #define SCREEN_HEIGHT 480 int randomInt(int min, int max) { return min + rand() % (max - min + 1); } void render(SDL_Renderer *renderer) { Uint8 r, g, b; /* Clear the screen */ SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255); SDL_RenderClear(renderer); /* Come up with a random rectangle */ SDL_Rect rect; rect.w = randomInt(64, 128); rect.h = randomInt(64, 128); rect.x = randomInt(0, SCREEN_WIDTH); rect.y = randomInt(0, SCREEN_HEIGHT); /* Come up with a random color */ r = randomInt(50, 255); g = randomInt(50, 255); b = randomInt(50, 255); SDL_SetRenderDrawColor(renderer, r, g, b, 255); /* Fill the rectangle in the color */ SDL_RenderFillRect(renderer, &rect); /* update screen */ SDL_RenderPresent(renderer); } int main(int argc, char *argv[]) { SDL_Window *window; SDL_Renderer *renderer; int done; SDL_Event event; /* initialize SDL */ if (SDL_Init(SDL_INIT_VIDEO) < 0) { printf("Could not initialize SDL\n"); return 1; } /* seed random number generator */ srand(time(NULL)); /* create window and renderer */ window = SDL_CreateWindow(NULL, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, SDL_WINDOW_OPENGL); if (!window) { printf("Could not initialize Window\n"); return 1; } renderer = SDL_CreateRenderer(window, -1, 0); if (!renderer) { printf("Could not create renderer\n"); return 1; } /* Enter render loop, waiting for user to quit */ done = 0; while (!done) { while (SDL_PollEvent(&event)) { if (event.type == SDL_QUIT) { done = 1; } } render(renderer); SDL_Delay(1); } /* shutdown SDL */ SDL_Quit(); return 0; } 

Этот код отображает прямоугольники со случайными цветами на случайных областях экрана. Скопируйте этот код в файл main.c.

Наконец, задайте для свойства « Пути поиска заголовка пользователя» папку, в которой находятся файлы заголовков SDL. Самый простой способ сделать это — создать символическую ссылку, которая указывает на папку SDL внутри проекта HelloSDL, и установить для свойства « Пути поиска заголовка пользователя» значение SDL / include / .

Пути поиска в заголовке пользователя

Убедитесь, что HelloSDL является активной схемой на панели инструментов, затем создайте и запустите проект, чтобы увидеть танцующие прямоугольники.

Прямоугольники

Вывод

Как вы видели, разработка C и C ++ в iOS проста благодаря использованию Objective-C ++. Если раньше вы программировали на C или C ++, то теперь проще перейти к разработке под iOS и использовать имеющиеся у вас навыки. Лучше всего то, что вы можете воспользоваться существующими библиотеками C / C ++, такими как мощный SDL с минимальной конфигурацией.

Я хотел бы услышать ваш опыт и мнения об использовании Objective-C ++ в комментариях ниже.