- Objective C on Windows
- Objective C on Windows
- Objective c from windows
- Способы встраивания C++ в Objective-C проекты
- Способы встраивания C++ в Objective-C проекты
- Зачем смешивать Objective-C и C++?
- Приводя к общему знаменателю: С
- Objective-C++ и проблемы с заголовочными файлами
- Стреляя в собственную ногу: void*
- Условная компиляция
- Абстрактные классы, интерфейсы и протоколы
- Абстрактные классы в Objective-C
- Pimpl
- Ограничения
Objective C on Windows
In this section you will learn how to use Objective C on Windows machine. We will download and install Objective C Windows compiler.
In this section you will learn how to use Objective C on Windows machine. We will download and install Objective C Windows compiler.
Objective C on Windows
In this section you will learn how to use Objective C on Windows machine. We will download and install Objective C Windows compiler. On windows GNU C compiler can be used to compile the Objective C program.
Objective C Compiler for Windows
The GNUstep windows installer can be downloaded and installed on the windows system to compile the Objective program. GNUset is objective c compiler for windows, that we will be using in our tutorial. The objective c compiler for windows can be downloaded from http://www.gnustep.org/experience/Windows.html.
Follow the following steps to download and install Objective C compiler for your windows system:
- Download:
Go to the site http://www.gnustep.org/experience/Windows.html and download the GNUsetup installer from the there. In our case the downloaded file is gnustep-system-0.19.2-setup.exe. Then double click on the downloaded file gnustep-system-0.19.2-setup.exe and install it on your system. - Set environment variable for GCC compiler (C:\GNUstep\mingw\bin\gcc.exe).
- Open start -> programs -> GNUstep -> shell
This is like a command prompt in windows.
Congratulations! You have successfully installed the GNUsetp to compile and run Objective C program on your windows system. In the next section we will show you how to run the compile and run the Objective program on windows environment.
Objective c from windows
Welcome to the Windows Bridge for iOS Project
The Windows Bridge for iOS (also referred to as WinObjC) is a Microsoft open-source project that provides an Objective-C development environment for Visual Studio and support for iOS APIs. The bridge allows you to create Universal Windows Platform (UWP) apps that will run on many Windows devices by re-using your Objective-C code and iOS APIs alongside Windows 10 features like Cortana and Windows Notifications.
Build and Release Status
Stable (master) | Pre-release (develop) | |
---|---|---|
Build | ||
GitHub Release | — | |
winobjc-tools | ||
WinObjC.Language | ||
WinObjC.Frameworks |
Download and Installation
To use the bridge you’ll need:
Windows 10, build 10586 or higher. Validate your version number here.
Visual Studio 2017 with Windows developer tools. Visual Studio 2017 Community is available for free here.
Ensure the following individual components are selected during installation. Selecting the Universal Windows Platform development workflow should give most of the below
NOTE: Please also install the Mobile development with .NET workflow option (Xamarin Tools) due to a bug in Nugetizer (See Issue 5026)
(Click to Expand)
- Visual Studio Core Editor
- Nuget Package Manager
- C# and Visual Basic Roslyn compilers
- Static analysis tools
- Windows 10 SDK (10.0.14393.0)
- Visual Studio C++ core features
- VC++ 2017 v141 toolset (x86, x64)
- Visual C++ compilers and libraries for ARM
- Visual C++ runtime for UWP
- Windows 10 SDK (10.0.10240.0)
- Windows 10 SDK (10.0.10586.0)
- MSBuild
- Windows Universal CRT SDK
- Standard Library Modules
- VC++ 2015.3 v140 toolset (x86,x64)
- Windows Universal C Runtime
To get started with an existing Xcode Project, you will also need:
- Chocolatey, a package manager for windows. See how to install the latest version here
- winobjc-tools, the command line tools for WinObjC. Run the below command from powershell (Admin) to get the latest version:
(more information about this command and its options can be found here. If you want to use develop packages add —pre to the command.)
Getting Started With the Bridge
Importing your Xcode Project
When using the bridge, the first thing you’ll want to do is generate a Visual Studio solution from your Xcode project:
- Open Windows PowerShell (type powershell in the Start Menu to find it) and navigate to your Xcode project directory using the cd command. Note: use the directory containing your .workspace or .xcodeproj folder.
- Run the vsimporter tool. This will generate the Visual Studio Solution:
- Open the generated Visual Studio solution with the command:
For more detailed step by step instructions on how to import a project, see the Quick Start Tutorial page of the wiki. For vsimporter options and known issues, check the Using vsimporter wiki page.
Building & Running the Samples
A great way to learn more about the bridge and its features is building and running the samples of the SDK, which contain many code examples. We recommend starting with the WOCCatalog sample app, which demonstrates an assortment of iOS and XAML UI controls:
- Clone the repo.
- Navigate to the samples/WOCCatalog directory of the bridge SDK
- Double-click on the WOCCatalog-WinStore10.sln solution to open it in Visual Studio
- In Visual Studio, right-click on the WOCCatalog (Universal Windows) project
- Select Set as StartUp project
- Use Ctrl-F5 to build and run the app
For more detailed step by step instructions, see the Quick Start Tutorial page of the wiki.
The following resources will help you get started. For more information, check out:
- Wiki, for documentation and tutorials
- Development Roadmap, detailing our highest priorities
- Website on Windows Dev Center, for evaluation virtual machines
- Quick Start Challenge, for a quick hands-on introduction to the bridge
- FAQ, with common questions and issues
- The iOS Bridge Samples Repo, for sample apps and code using the bridge
There are many ways to contribute to the Windows Bridge for iOS:
- Submit bugs & issues and help us verify fixes as they are checked in.
- Review source code changes.
- Submit a bug fix or feature implementation via pull request.
- Follow @WindowsDev on Twitter and join the discussion using the #WinObjC hashtag.
- Engage with other users and developers on StackOverflow and tag your questions with WinObjC.
See our contribution guidance in the wiki for more details on how to contribute to the project.
This project has adopted the Microsoft Open Source Code of Conduct. For more information see the Code of Conduct FAQ or contact opencode@microsoft.com with any additional questions or comments.
Advanced Installation for Contributors and Ninjas
Additional Visual Studio Components Needed for Contributors:
- C# and Visual Basic
- Visual Studio SDK
- .NET Framework 4.6 targeting pack
- C++ Profiling Tools
If you want to build the bridge from source instead, you’ll also need to install Git LFS before cloning the repo. For more detailed instructions, see the Building From Source wiki page.
If you’re having trouble downloading & installing the bridge, see the Known Issues section below and check our FAQ.
For details on our planned features and future direction sort the list of issues by milestone and refer to our roadmap.
Способы встраивания C++ в Objective-C проекты
Этот топик — мой перевод статьи про способы встраивания С++ в Objective-C проекты, в которой рассказаны некоторые интересные решения, как удачные, так и неудачные. Оригинал статьи:
www.philjordan.eu/article/strategies-for-using-c++-in-objective-c-projects
Способы встраивания C++ в Objective-C проекты
95% случаев. Остальная часть содержит более глубокий анализ проблемы и дополнительные методы ее решения.
Зачем смешивать Objective-C и C++?
Используя Objective-C, обычно для программирования под iOs или под Mac, я часто сталкивался с ситуациями, когда нужно было вставить С++ в проект. Иногда самая хорошая библиотека для текущей задачи была написана на С++, иногда решение проблемы можно было более лаконично сделать на С++. Самый банальный пример — шаблоны С++, спасающие от написания повторяющегося стандартного кода. Менее очевидно то, что Objective-C иногда слишком объектно-ориентирован. Это звучит как ересь для «людей-для-которых-каждый-предмет-это-объект», но для нетривиальных структур данных я зачастую нахожу объектную ориентацию слишком громоздкой, а Сишные структуры слишком слабыми. Использование же С++ подходит в самый раз.
Objective-C также довольно агрессивен в плане управления памятью, когда нет, например, сборщика мусора. STL (и его новое расширение shared_ptr) позволяет забыть про эту проблему, или, по крайней мере, сосредоточить ее в конструкторах/деструкторах, а не захламлять код release’ами и retain’ами. Конечно, это дело вкуса, и зависит от ситуации; автоматическое управление памятью помогает в коде со нетривиальными структурами данных или в алгоритмически сложном коде.
Еще один повод для смешивания Objective-C и C++ — противоположная ситуация, когда необходимо вызывать функции Objective-C из проекта С++. Распространенный пример — портирование игры или движка под платформы Apple. В таких случаях также можно применять описанные ниже приемы.
Наконец, можно использовать С++ для улучшения производительности. Гибкость сообщений Objective-C накладывает некоторые издержки по сравнению с реализацией большей части виртуальных функций С++, даже учитывая техники кэширования, которые используются в современных рантаймах. Объекты Objective-C не имеют эквивалентных быстрых невиртуальных функций С++. Для оптимизации это может быть важным фактором.
Приводя к общему знаменателю: С
Один из возможных способов использовать эти два языка программирования в одном проекте — полностью разделить их, позволив взаимодействовать через чистый С. Таким образом, можно будет предотвратить их «смешение». Выглядеть это будет так: код, использующий библиотеку С++ переносится в .cpp файл, интерфейс объявлен в заголовочном файле С, С++ часть реализует этот интерфейс с помощью extern «C» функций, а код, в котором будет происходить обращение к интерфейсу С — чистый Objective-C (.m).
Это будет работать неплохо в простых случаях, но более вероятно, что придется писать некоторую оболочку. Тот, у кого есть опыт динамически подгружаемых С++ библиотек с помощью открытого интерфейса С хорошо это знает.
Сегодня фактически весь Objective-C компилируется с помощью GCC или clang. Оба компилятора поддерживают Objective-C++, а это означает, что существует более удобный способ смешать языки.
Objective-C++ и проблемы с заголовочными файлами
На первый взгляд, использование диалекта Objective-C++ выглядит самым прямолинейным подходом. Это результат слияния С++ и Objective-C вместе в одном компиляторе, надежные реализации которых есть и в GCC, и в clang. Учитывая то, насколько различны Objective-C и C++, программисты GCC сделали трудоемкую работу. Но стоит только начать переименовывать .m файлы в .mm для их объявлени как С++ файлов, приходит понимание, что не все так просто.
Заголовочные файлы и препроцессор С на протяжении многих лет являются причиной головной боли программистов С, С++ и Objective-C, а при смешивании этих языков все становится еще хуже. Допустим, необходимо использовать контейнер map(словарь, ассоциативный массив) из библиотеки STL в классе Objective-C. Насколько я знаю, фреймворк Foundation от Apple не содержит отсортированного map’a, структурно построенного на деревьях. Итак, создаем переменную-член в нашем классе:
Однако, std::map имеет смысл только для компилятора, поддерживающего С++, и только после #include , так что теперь этот заголовочный файл может быть импортирован (#import) только из файлов Objective-C++. А любой код, использующий этот класс теперь должен быть конвертирован в Objective-C++. Далее, по цепочке, остальные заголовочные файлы также придется конвертировать (.mm), и так со всем проектом.
В некоторых случаях это допустимо. Несмотря на это, менять весь проект или его большую часть только для того, чтобы в одном месте использовать библиотеку, — слишком громоздко и избыточно; кроме того, если вы единственный в проекте среди Objective-C программистов, знающий С++, это будет не очень хорошей идеей. Кроме того, проблемы могут возникнуть при компиляции кода на чистом С компилятором С++, редко случается, что такое проходит полностью безболезненно. Сверх того, это значит, что код нельзя будет повторно использовать автоматически в других проектах Objective-C.
В большинстве же случаев, выход, позволяющий использовать преимущества кода на чистом Objective-C или C++ — это использование Objective-C++ там, и только там, где необходимо. Чтобы сделать это идеально, придется постараться.
Стреляя в собственную ногу: void*
Становится понятно, что цель — убрать все, что есть от С++, из заголовочных файлов. Типичный для С способ скрыть тип — указатель на void. Здесь, конечно, это тоже будет работать:
В тех местах кода, где будет использоваться таблица, придется использовать явное приведение типов: static_cast *>(lookupTable) или ((std::map *)lookupTable), что будет сильно раздражать. Если действительный тип члена класса изменится, все приведения типов придется менять вручную, а это резко увеличивает вероятность ошибиться. С ростом числа членов запомнить все правильные типы становится невозможно, и в итоге получаем недостатки как статического, так и динамического типизирования. Использование этого способа для работы с объектами из иерархии классов — это опасная игра с огнем, в которой может еще и оказаться, что указатели А* и В* на один и тот же объект имеют разные представления void*
Можно сделать и лучше.
Условная компиляция
Потеря информации о типе — это плохо, но раз уж типизированные поля С++ используются из кода Objective-C, а чистому Objective-C компилятору необходимо знать только об их присутствии (для корректного выделения памяти), почему бы не сделать две различные версии кода? В Objective-C++ определен символ препроцессора _cplusplus, поэтому как насчет такой реализации:
Некрасиво, но с этим гораздо легче работать. Стандарт С++ не гарантирует, что указатель на класс и указатель на void будут иметь одно и то же расположение в памяти (объект, конечно, один), но Objective-C++ не является стандартом GNU/Apple. На практике же проблему представляют только указатели на виртуальные функции, когда происходит конвертация в void*, а при попытке это сделать компилятор будет громко ругаться. Если же беспокойство не проходит, можно использовать static_cast<> вместо приведения в стиле С.
С по-прежнему удачно приводит void* к любому другому указателю неявным образом, поэтому, возможно, предпочтительно было бы заменить Сишную часть с #ifdef на указатель на структуру со сложным, но уникальным и узнаваемым названием, например, struct MyPrefix_std_map_int_id. Можно даже определить макро, расширяющееся в корректное определение типа в зависимости от компилятора:
При таком способе не получится избежать условного #include заголовков С++, а это может запутать людей, которые не знают или не любят С++. Да и выглядит это не очень. К счастью, есть другие решения.
Абстрактные классы, интерфейсы и протоколы
Многие С++ программисты хорошо знакомы с чисто виртуальными функциями, и, следовательно, абстрактными классами. Другие языки, такие как Java и С#, имеют явную концепцию «интерфейса», при которой намеренно скрываются детали реализации. Этот же паттерн можно использовать и в нашем случае.
Последние версии Objective-C поддерживают протоколы, похожие на интерфейсы Java/C# по сути, если не по синтаксису. Можно объявить открытые методы класса в протоколе в заголовочном файле, а объявить и написать конкретный класс, реализующий указанный протокол, в закрытом коде (разделив таким образом, С++ и Objective-C). Это будет работать для методов экземпляра, но не получится напрямую создать экземпляр класса через протокол. Поэтому придется делегировать распределение памяти и инициализацию новых объектов фабрике классов или функции С. Хуже то, что протоколы в каком-то смысле ортогональны классам, поэтому при объявлении ссылки будут выглядеть по-другому:
Все работает, но и это не идеал.
Абстрактные классы в Objective-C
Так что там насчет абстрактных классов? В этом языке нет прямой идиоматической поддержки для них, но даже распространенный NSString является абстрактным, и невозможно понять это, просто используя его. Один из альтернативных способов решения нашей проблемы — взять все объявления методов и поместить их все в такой класс. Придется терпеть предупреждения компилятора о неполном описании класса. В рантайме попытки вызвать несуществующий метод будут бросать исключения. Можно, конечно, создать псевдо-реализации этих методов, которые будут бросать специальные исключения, объясняющие ситуацию.
В большинстве языков для создания экземпляров нужно знать конкретный класс, либо делегировать это фабрике классов. Занимательно, что можно напрямую послать классу NSString сообщения alloc и init, а получить экземпляры классов, унаследованных от NSString. Сообщения init возвращают объект, отличный от self, которому было послано init, например, alloc у NSString может быть переопределен так, что вызывается NSCFString, тут фабрикой классов является NSString. Если делать такое самому — придется определить все init* методы, используемые конкретным классом, для абстрактного, иначе они не будут видны тем, кто им пользуется.
Таким образом, объявить все методы в абстрактном классе, наслеюдуя от него Objective-C++ классы — определенно самое непыльное решение для заголовочного файла и для тех, кто пользуется этим классом, но, одновременно, оно является самым трудоемким, требующим дополнительного класса, псевдо-методов и нетривиальных реализаций init.
Однако же, программисты С++ нашли элегантное решение подобным проблемам. Одна из серьезных проблем больших проектов С++ — это резко возрастающее время компиляции, связанное с зависимостями заголовочных файлов. В таких случаях обычно делается сокрытие внутренностей класса от использующих его программистов. Точно такое же решение можно применить к дилемме Objective-C/C++.
Pimpl
Pimpl — сокращение от «указатель на реализацию» (pointer to implementation) или «закрытая реализация» (private implementation). Эта идиома довольно проста. В открытом заголовочном файле добавляется опережающее описание реализации struct, обычно, используя имя открытого класса с суффиксом Impl, зависит от соглашения. Эта struct будет содержать все члены, которые необходимо спрятать от открытого заголовочного файла класса. Осталось добавить указатель на структуру в переменные класса и определить члены структуры в .cpp файле (в нашем случае — .mm). В конструкторе (точнее, в -init*), с помощью оператора new нужно создать экземпляр структуры, присвоить ее переменной класса и убедиться, что в -dealloc вызывается delete.
Все будет работать, потому что опережающее объявление структур — это допустимый код на С, даже если потом окажется, что в структуре присутствуют явные или неявные конструкторы С++ или даже родительские классы. Открытые методы класса имеют доступ к стуруктуре через указатель, а создание и удаление происходит с помощью new/delete.
Зависит от реализации, насколько большая функциональность будет у методов открытого класса. Можно повысить производительность, если в некоторых случаях избежать пересылки сообщений Objective-C, но стоит помнить о неприятностях, которые могут возникнуть, когда методы С++ должны посылать сообщения классам Objective-C.
Стоит отметить, что вместо реализации в MyClass структуры, можно унаследовать от нее MyClass. Так можно избежать непрямых вызовов:
Но с увеличением количества членов это становится непрактичным из-за большого количества new/delete.
Ограничения
На чистом С++ имплементацию можно сделать классом, но в нашем случае это не пройдет, так как опережающее объявление должно быть корректным на Objective-C. В литературе по С++ можно встретить рекомендации использования shared_ptr<> и auto_ptr<> для автоматического удаления объектов. В заголовочных файлах Objective-C такое тоже не пройдет. Также не удасться уйти от указателя на струткуру, так как компилятор должен знать, сколько под нее необходимо выделить памяти.
Имплементация закрыта, поэтому невозможен прямой доступ к членам классов-наследников. Тем не менее, можно вынести объявления структуры в полу-закрытый заголовочный файл, который будет включаться только классами-наследниками, которые должны иметь этот прямой доступ. Такие наследники должны быть написаны на Objective-C++.