Нужно ли импортировать заголовки файлов в языке swift
Данная статья является обощением найденной информации, а также полученного опыта. Подчеркну, она не претендует на то, чтобы называться, как говорится, хорошей практикой, а лишь предлагает возможные действия в описанных обстоятельствах или является неким академическим экспериментом.
Последнее обновление – февраль 2019 г.
TL;DR. Чтобы использовать «Swift»-код внутри «Objective-C» придется поступиться некоторыми «фичами» «Swift» и написать обертку над кодом, которая не будет использовать несовместимые с «Objective-C»-приемы («structures», «generics», «enum associated values», «protocol extensions» и пр.), а будет основываться на классах-наследниках NSObject .
Импорт кода внутри Framework
Чтобы использовать объявления Objective-C в файлах в той же цели фреймворка, что и ваш Swift-код, настройте зонтичный заголовок следующим образом:
- В разделе Build Settings, в Packaging, убедитесь, что параметр Defines Module для цели фреймворка установлен на Yes.
- В зонтичном заголовке импортируйте все заголовки Objective-C, которые вы хотите раскрыть для Swift.
Swift видит каждый заголовок, который вы открыто раскрываете в зонтичном заголовке. Содержимое файлов Objective-C в этом фреймворке автоматически доступно из любого файла Swift внутри этого фреймворка, без каких-либо операторов импорта.
Используйте классы и другие объявления из вашего кода Objective-C с тем же синтаксисом Swift, который вы используете для системных классов.
Привет, Хабр! 2 июня все мы воочию могли наблюдать, как компания Apple начала творить революцию в стане Objective-C разработчиков, представив миру свой новый язык программирования – Swift. Вместе с этим, она выложила в открытый доступ небольшую документацию по языку, которую мы решили перевести, если на то будет спрос. Предлагаем вашему вниманию перевод первой главы. Если тема будет интересна, то мы продолжим публиковать перевод каждую неделю.
Оглавление
Language guide
The Basics
Basic Operators
String and Characters
Collection Types
Control Flow
Functions
Closures
Enumerations
Classes and Structures
Properties
Methods
Subscripts
Inheritance
Initialization
Deinitialization
Automatic Reference Counting
Optional Chaining
Type Casting
Nested Types
Extensions
Protocols
Generics
Advanced Operators
Language Reference
About the Language Reference
Lexical Structure
Types
Expressions
Statements
Declarations
Attributes
Patterns
Generic Parameters and Arguments
Summary of the Grammar
Trademarks
О языке Swift
Swift – это новый язык программирования для разработки iOS и OS X приложений, который сочетает в себе все лучшее от C и Objective-C, но лишен ограничений, накладываемых в угоду совместимости с C. В Swift используются паттерны безопасного программирования и добавлены современные функции, превращающие создание приложения в простой, более гибкий и увлекательный процесс. Swift, созданый нами с чистого листа, – это возможность заново представить себе, как разрабатываются приложения.
Swift разрабатывался нами несколько лет. Основой нового языка программирования послужили существующие компилятор, отладчик и фреймворки. Мы упростили процесс управления памятью с помощью механизма автоматического подсчета ссылок – Automatic Reference Counting (ARC). Наши фреймворки также подверглись серьезной модернизации. Objective-C начал поддерживать блоки, литералы и модули – все это создало благоприятные условия для внедрения современных технологий. Именно эта подготовительная работа послужила фундаментом для нового языка программирования, который будет применяться для разработки будущих программных продуктов для Apple.
Разработчикам Objective-C Swift покажется знакомым. Он сочетает в себе читабельность именованных параметров и мощь динамической объектной модели Objective-C. Он открывает доступ к уже существующим фреймворкам Cocoa и совместим с кодом, написанным на Objective-C. Построенный на этой общей основе язык предлагает множество новых возможностей и унифицирует процедурные и объектно-ориентированные аспекты языка программирования.
Swift не отпугнет и начинающих программистов. Это первый мощный язык программирования, такой же понятный и увлекательный, как скриптовый язык. Он поддерживает так называемые playground-ы, которые позволяют программистам экспериментировать с кодом, видя результат в режиме реального времени без необходимости компилировать и запускать приложение.
Swift вобрал в себя все лучшее от современных языков и разработан с учетом обширного опыта компании Apple. Наш компилятор – синоним производительности, наш язык оптимизирован для разработки без оглядки на компромиссы. Он спроектирован таким образом, чтобы вы смогли легко разработать и ваше первое приложение «hello, world!», и даже целую операционную систему. Все это делает Swift важным инструментом для разработчиков и для самой компании Apple.
Swift – это новый фантастический способ создавать приложения для iOS и OS X, и мы продолжим развивать его, добавляя новый функционал и представляя новые возможности. Наша цель – амбициозна. И мы с нетерпением ждем, чтобы увидеть, что вы сумеете создать при помощи него.
Введение в Swift
По давней традиции первая программа на новом языке должна выводить на экран слова “Hello, world” . С помощью Swift это делается так:
Если вы когда-нибудь разрабатывали на C или Objective-C этот синтаксис должен казаться вам до боли знакомым – в Swift эта строчка кода является законченной программой. Вам больше не нужно импортировать отдельные библиотеки для обеспечения базового функционала вроде ввода/вывода в консоль или работы со строками. Код, написанный в глобальной области видимости, является точкой входа в программу, таким образом функция main больше не нужна. Также обратите внимание на отсутствие точки с запятой в конце каждой строки.
Это введение содержит достаточно информации, чтобы начать писать код на Swift. Не переживайте, если вам будет что-то непонятно – мы все детально объясним в последующих главах.
Замечание
Для лучшего понимания материала мы рекомендуем использовать режим playground в Xcode. Playground позволяет вам видеть результат сразу в процессе редактирования кода без необходимости компилировать и запускать приложение.
Простые типы данных
Используйте let для создания константы и var для создания переменной. Тип константы указывать не нужно, вы можете присвоить ей значение лишь единожды.
Типы константы и переменной должны совпадать с типами присваиваемых им соответствующих значений. Однако это не означает, что вы должны напрямую указывать их тип. Компилятор автоматически определит тип константы и переменной при присваивании им значения. Так, в приведенном примере компилятор определит, что myVariable имеет целочисленный тип.
Если же инициализатор отсутствует или не предоставляет достаточной информации, вы можете указать тип самостоятельно после переменной, разделив название и тип двоеточием:
Значения никогда не конвертируются в другой тип неявно. Если вам необходимо конвертировать значение в другой тип, делайте это явно:
Давайте поэкспериментируем
Попробуйте удалить явное преобразование к типу String в последней строке. Какую ошибку вы получите?
Имеется более простой способ включения значений в строки: для этого заключите выражение в скобки и поставьте перед ними обратный слэш ( \ ). Пример:
Давайте поэкспериментируем
Попробуйте использовать конструкцию \() и выведите на экран строку, включающую результат суммы двух целочисленных переменных и чье-нибудь имя.
При работе с массивами и ассоциативными массивами (словарями, dictionary) используются квадратные скобки ( [] ):
Чтобы создать пустой массив или dictionary, используйте следующий синтаксис:
Для создания пустых массивов и словарей используйте [] и [:] соответственно, – например, когда вы присваиваете новое значение переменной или передаете аргумент в функцию.
Условия и циклы
Для создания условий используются операторы if и switch , для создания циклов – for-in , for , while и do-while . При этом выделять круглыми скобками условия и инициализирующие выражения необязательно, тогда как фигурные скобки обязательны.
Условие внутри оператора if должно быть логическим, это в частности означает, что выражение if score является ошибочным, поскольку здесь нет явного сравнения (например, с нулем).
Условный оператор if можно использовать совместно с let и var для работы с константами и переменными, которые могут иметь значение nil . Такие константы и переменные называются опциональными (то есть они могут либо принимать какое-либо значение, либо быть равны nil ). Чтобы создать опциональную переменную или константу добавьте знак вопроса ( ? ) после указания типа.
Давайте поэкспериментируем
Измените optionalName на nil . Что вы видите на экране? Добавьте блок else для обработки случая, когда optionalName равен nil .
Если опциональное значение равно nil , условие будет ложным и код в фигурных скобках после if выполнен не будет. В противном случае переменной greeting будет присвоено новое значение.
Оператор множественного выбора switch поддерживает внутри себя множество других операторов сравнения и не ограничен лишь простыми сравнениями:
После выполнения подходящего блока кода, программа покидает оператор switch , не проверяя последующие условия. Таким образом вам не нужно вручную добавлять операторы прерывания ( break ) в конце каждого блока case .
Для перебирания элементов ассоциативного массива используйте оператор for-in совместно с указанием пары имен для каждой пары ключ-значение.
Давайте поэкспериментируем
Добавьте еще одну переменную, которая позволит выяснить, к какому из трех типов относится найденное максимальное число.
Оператор цикла while позволяет выполнять блок кода внутри него до тех пор, пока условие не станет ложным. Условие также может быть указано после блока, который в таком случае будет выполнен по крайней мере один раз.
Оператор for можно использовать для перебора последовательности чисел с помощью двух точек ( .. ) или с помощью инициализатора, условия и инкремента. Посмотрите, эти два цикла делают одно и то же:
При создании цикла используйте две точки ( .. ), если не хотите включать большее значение в диапазон, и три точки ( … ), чтобы включить как меньшее, так и большее значения.
Функции и замыкания.
Для объявления функций используйте ключевое слово func . Вызов функции производится через указание ее имени и списка аргументов в круглых скобках. Возвращаемый тип следует отделить от перечня формальных аргументов с помощью -> .
Давайте поэкспериментируем
Удалите параметр day. Вместо него добавьте переменную, обозначающую наименование подаваемого на обед блюда.
Если функция возвращает множество значений, следует использовать кортеж:
Функции также могут иметь неопределенное число аргументов:
Давайте поэкспериментируем
Напишите функцию, позволяющую находить среднее арифметическое произвольного числа своих аргументов.
Функции могут вкладываться друг в друга. Вложенная функция может обращаться к переменным, объявленным во внешней функции. Используйте вложенные функции, чтобы привести в порядок код сложной или большой функции.
Функции являются объектами первого класса (first-class type), иными словами, функция в качестве свого результата может возвращать другую функцию.
Функция также может принимать другую функцию в качестве одного из аргументов.
Функции являются частным случаем замыканий. Вы можете создать замыкание, не указывая его имени и окружив тело замыкания фигурными скобками ( <> ). Для отделения аргументов и типа возвращаемого значения от тела замыкания используйте оператор in .
Давайте поэкспериментируем
Перепишите замыкание таким образом, чтобы оно возвращало ноль для всех лишних чисел.
Существует несколько техник, позволяющих делать замыкания более лаконичными. Если тип замыкания априори известен (например, это callback делегата), можно опустить указание типа его параметров и/или типа возвращаемого значения. Замыкания, состоящие из единственного выражения, неявно возвращают результат этого выражения.
В замыкании вместо указания имени переменной, вы можете использовать ее порядковый номер – это особенно полезно при написании коротких замыканий. Замыкание, являющееся последним аргументом функции, может быть передано в нее сразу после круглых скобок с перечнем остальных параметров.
Объекты и классы
Для создания класса используется зарезервированное слово class . Члены класса объявляются точно так же, как и обычные константы и переменные. Более того, методы класса объявляются как обычные функции.
Давайте поэкспериментируем
Добавьте константу-член класса и метод класса, принимающую ее в качестве своего аргумента.
Чтобы создать экземпляр (объект) класса, достаточно добавить круглые скобки после названия класса. Доступ к методам и членам класса осуществляется через точку.
В этом примере мы упустили одну важную деталь – конструктор класса, метод init .
Обратите внимание, как член класса name при помощи self отделен от аргумента конструктора name . Аргументы передаются в конструктор обычным образом, как и в любой другой метод класса. Обратите внимание на то, что каждый член класса должен быть проинициализирован – либо при объявлении (как, например, numberOfSides ), либо в конструкторе (как name ).
Деструктор класса – метод deinit , который можно переписать в случае необходимости.
Чтобы наследовать класс от уже существующего класса, после указания имени дочернего класса следует поставить двоеточие и указать название родительского. В Swift нет никаких ограничений по обязательному наследованию какого-либо стандартного класса.
Переопределенные дочерним классом методы должны быть помечены ключевым словом override – переопределение методов без override приведет к ошибке. Компилятор также выявляет методы, маркированные override , но не переопределяющие какие-либо методы своего родительского класса.
Давайте поэкспериментируем
Создайте класс Circle и наследуйте его от класса NamedShape . Конструктор класса Circle принимает два аргумента – радиус и название. Переопределите методы area и describe этого класса.
Члены класса могут также иметь собственные getter и setter .
В setter -е переменной perimeter новое присваиваемое значение неявно называется newValue . Вы можете изменить название этой переменной, указав его в скобках сразу после set .
- инициализация членов дочернего класса;
- вызов конструктора родительского класса;
- изменение значений членов родительского класса.
У методов классов имеется одно важное отличие от функций. Названия аргументов функции используются только в пределах этой функции, тогда как в методе класса параметры также используются при вызове этого метода (кроме первого параметра). По умолчанию метод класса имеет одинаковые названия параметров как при вызове, так и внутри себя. Однако вы можете указать другое название (в примере ниже – times ), которое будет использовано только внутри этого метода. При этом для вызова этого метода необходимо использовать первое название ( numberOfTimes ).
При работе с опциональными значениями добавьте знак вопроса ( ? ) перед методами, членами класса и т.д. Если значение перед знаком вопроса равно nil , все, что следует после ( ? ) игнорируется и значение всего выражения равно nil . В противном случае выражение вычисляется обычным образом. В обоих случаях результатом всего выражения будет опциональное значение.
Перечисления и Структуры
Для создания перечислений используется ключевое слово enum . Отметим, что перечисления также могут иметь в своем составе методы.
Давайте поэкспериментируем
Напишите функцию, которая сравнивает 2 перечисления типа Rank по их значениям.
В вышеприведенном примере элементы перечисления первоначально имеют целочисленный тип, и вам достаточно указать значение только первого элемента – значения остальных элементов будут определены в соответствии с порядком их следования. В качестве исходного типа (raw value) значений элементов вы также можете выбрать строковый или вещественные типы.
Для преобразования исходного типа значения в тип перечисления используйте функции toRaw и fromRaw .
Отметим, что значения элементов перечисления являются фактическими, а не просто иной записью своих исходных значений. Вообще говоря, вы можете и не указывать их исходные значения.
Давайте поэкспериментируем
Добавьте метод Color , возвращающий строку “black” для Spades и Clubs и “red” для Hearts и Diamonds .
Обратите внимание на то, как осуществляется доступ к члену Hearts перечисления Suit . При присваивании значения константе hearts используется полное имя Suit.Hearts , поскольку мы явно не указываем тип этой константы. А в switch мы используем сокращенную форму .Hearts , поскольку тип значения self априори известен. Вы можете использовать сокращенную форму повсеместно, если тип переменной явно указан.
Для создания структур используется ключевое слово struct . Структуры имеют множество схожих черт с классами, включая методы и конструкторы. Одним из наиболее существенных отличий структур от классов является то, что экземпляры структур, в отличие от экземпляров классов, передаются в функции по значению (то есть предварительно создается их локальная копия), тогда как экземпляры классов передаются по ссылке.
Экземпляр члена перечисления может иметь собственные значения и они могут быть разными. Вы присваиваете эти значения при создании экземпляра перечисления (константа success в примере). Связанные и исходные значения это разные вещи: исходное значение члена перечисления всегда постоянно для всех экземпляров перечисления и указывается при его объявлении.
Обратите внимание, каким образом из объекта ServerResponse “вытаскиваются” время восхода и заката.
Протоколы и Расширения.
Для объявления протокола используйте ключевое слово protocol .
Протоколы могут поддерживаться классами, перечислениями и структурами.
Обратите внимание на ключевое слово mutating в определении структуры SimpleStructure , которое информирует компилятор о том, что соответствующий метод подвергает структуру изменениям. В противовес этому методы класса SimpleClass не нужно маркировать как mutating , поскольку методы класса всегда могут беспрепятственно его изменять.
Для добавления новых методов или членов класса в уже существующий тип необходимо использовать расширения – extensions . Вы также можете использовать расширения для реализации протокола уже существующим типом, даже если он импортирован из какой-либо библиотеки или фреймворка.
Вы можете использовать название протокола как и любой другой тип – например, чтобы создать массив объектов разного типа, но реализующих общий протокол. Заметьте, что при работе с объектами такого типа методы, объявленные вне протокола, будут недоступны.
Несмотря на то, что во время выполнения программы переменная protocolValue имеет тип SimpleClass , компилятор считает, что ее тип – ExampleProtocol . Это означает, что вы не сможете случайно получить доступ к методам или членам класса, которые реализуются вне протокола ExampleProtocol .
Обобщенные типы (generics)
Для создания обобщенного типа, заключите имя в угловые скобки ( <> ).
Создавайте обобщенные функции, классы, перечисления и структуры.
Если вы хотите задать обобщенные типу определенные требования, такие, как, например, реализация протокола или требование быть наследованным от определенного класса, используйте where .
Давайте поэкспериментируем
Измените функцию anyCommonElements таким образом, чтобы она возвращала массив общих элементов.
В простых случаях вы можете опустить where и написать имя протокола или класса после двоеточия. Выражение эквивалентно выражению .
Импорт кода из того же приложения Target
Если Вы пишете приложение на разных языках, Вы, возможно, должны получить доступ к своему коду Objective C от Swift и своему Коду SWIFT от Objective C. Процесс, описанный в этом разделе, применяется к целям неплатформы.
Обзор смешивания и подгонки
Objective C и файлы Swift могут сосуществовать в единственном проекте, был ли проект первоначально проект Swift или Objective C. Можно просто добавить файл другого языка непосредственно к существующему проекту. Этот естественный поток операций делает создающее приложение на разных языках и цели платформы столь же прямыми как создание приложения или цели платформы записанный на единственном языке.
Процесс для работы с целями на разных языках отличается немного в зависимости от того, пишете ли Вы приложение или платформу. Общая импортная модель для работы с обоими языками в той же цели изображена ниже и описана более подробно в следующих разделах.
Импорт кода внутри приложения
Чтобы импортировать набор файлов Objective-C в код Swift в рамках одной и той же цели сборки приложения, вы полагаетесь на заголовочный файл Objective-C bridging header, чтобы открыть эти файлы для Swift.
Xcode предлагает создать подобный заголовок, когда вы добавляете файл Swift в существующее приложение Objective-C, либо файл Objective-C в существующее приложение Swift.
Скриншот приглашения Xcode для настройки мостового заголовка Objective-C.
Если вы соглашаетесь, Xcode создает файл связующего заголовка вместе с файлом, который вы создавали, и называет его с помощью имени вашего модуля продукта, за которым следует -Bridging-Header.h .
В качестве альтернативы, вы можете создать заголовок самостоятельно, выбрав File > New > File > [операционная система] > Source > Header File.
Отредактируйте связующий заголовок, чтобы открыть код Objective-C для кода Swift:
- Импортируйте в свой связующий заголовок Objective-C все заголовки Objective-C, которые вы хотите передать в Swift.
- В Build Settings, в Swift Compiler -> General, убедитесь, что в параметре сборки Objective-C Bridging Header указан путь к файлу связующего заголовка. Путь должен быть относительным к вашему проекту, подобно тому, как в Build Settings указывается путь к Info.plist . В большинстве случаев вам не потребуется изменять этот параметр.
Любые публичные заголовки Objective-C, перечисленные в мостовом заголовке, видны Swift. Декларации Objective-C автоматически доступны из любого файла Swift внутри этой цели сборки, без операторов импорта.
Используйте классы/объекты и другие объявления из вашего пользовательского кода Objective-C с тем же синтаксисом Swift, который вы используете для системных классов.
Именование Вашего модуля продукта
Имя сгенерированного XCode заголовка для Кода SWIFT и имя заголовка образования моста Objective C, который XCode создает для Вас, сгенерированы с Вашего имени модуля продукта. По умолчанию Ваше имя модуля продукта совпадает с Вашим названием продукта. Однако, если Ваше название продукта имеет какие-либо неалфавитно-цифровые символы, такие как период ( . ), они заменяются подчеркиванием ( _ ) на Ваше имя модуля продукта. Если имя начинается с числа, первое число заменяется подчеркиванием.
Можно также обеспечить пользовательское имя для имени модуля продукта, и XCode будет использовать это при именовании образования моста и сгенерированных заголовков. Чтобы сделать это, измените настройки сборки Имени Модуля продукта.
Перечисляемые типы в „Swift“ и „Objective-C“
При использовании перечисляемых типов „Swift“ в „Objective-C“-проектах есть только один нюанс: они должны иметь целочисленный Raw Type. Только после этого мы сможем аннотировать enum как @objc .
Что делать, если мы не можем изменить тип enum , но хотим использовать его внутри „Objective-C“? Мы можем, как обычно, обернуть метод, использующий экземпляры этого перечисляемого типа, и подсунуть ему наш собственный enum . Например:
Начало
Итак, у нас имеется «Objective-C»-проект и некий код на «Swift», который мы хотим использовать в этом проекте. Для примера, пусть это будет сторонний «Swift»-фреймфорк, который мы добавляем в проект, скажем, с помощью «CocoaPods». Как обычно, добавляем нужную зависимость в «Podfile», выполняем pod install , открываем «xcworkspace»-файл.
Чтобы импортировать фреймворк в «Objective-C»-файл не нужно ни прописывать import всего фреймворка, как мы привыкли это делать в «Swift», ни пытаться импортировать отдельные файлы публичных API фреймворка, как мы привыкли это делать в «Objective-C». В любой файл, в котором нам необходим доступ к функционалу фреймворка, мы импортируем файл с названием -Swift.h – это автоматически сгенерированный заголовочный файл, который является проводником «Objective-C»-файлов к публичным «API», содержащимся в импортированных «Swift»-файлах. Выглядит это примерно так:
Реализация «Swift»-протоколов «Objective-C»-классами
Для примера возьмем, конечно же, протокол, в параметрах или возвратных значениях методов которого используются «Swift»-типы, которые не могут быть использованы в «Objective-C:
Придется снова оборачивать. Для начала – SwiftClass :
Далее напишем свой протокол, аналогичный SwiftProtocol , но использующий обернутые версии классов:
Далее – самое интересное: объявим „Swift“-класс, адаптирующий нужный нам „Swift“-протокол. Он будет чем-то вроде моста между нашим протоколом, который мы написали для адаптации в „Objective-C“-проекте и „Swift“-методом, который принимает объект исходного „Swift“-протокола. В членах класса будет числиться экземпляр протокола, который мы описали. А методы класса в методах протокола будут вызывать методы написанного нами протокола:
К сожалению, без оборачивания метода, принимающего экземпляр протокола, не обойтись:
Не самая простая цепочка? Да. Хотя, если используемые классы и протоколы обладают ощутимым количеством методов, обертка уже не покажется такой непропорционально-объемной по отношению к исходному коду.
Собственно, использование протокола в самом „Objective-C“-кода будет выглядеть уже вполне гармонично. Реализация методов протокола:
И использование метода:
Начало
Итак, у нас имеется «Objective-C»-проект и некий код на «Swift», который мы хотим использовать в этом проекте. Для примера, пусть это будет сторонний «Swift»-фреймфорк, который мы добавляем в проект, скажем, с помощью «CocoaPods». Как обычно, добавляем нужную зависимость в «Podfile», выполняем pod install , открываем «xcworkspace»-файл.
Чтобы импортировать фреймворк в «Objective-C»-файл не нужно ни прописывать import всего фреймворка, как мы привыкли это делать в «Swift», ни пытаться импортировать отдельные файлы публичных API фреймворка, как мы привыкли это делать в «Objective-C». В любой файл, в котором нам необходим доступ к функционалу фреймворка, мы импортируем файл с названием -Swift.h – это автоматически сгенерированный заголовочный файл, который является проводником «Objective-C»-файлов к публичным «API», содержащимся в импортированных «Swift»-файлах. Выглядит это примерно так:
Заключение
У данного подхода, конечно, есть и свои минусы. Помимо самого очевидного (написание ощутимого количества дополнительного кода), есть еще один немаловажный: „Swift“-код переносится в среду выполнения „Objective-C“ и будет работать, скорее всего, уже не так быстро или, по-крайней мере, иначе. Хотя разница во многих случаях невооруженным взглядом заметна не будет.
Разработчик
Используя Swift с какао и Objective C
iBook
- Обзор смешивания и подгонки
- Импорт кода из того же приложения Target
- Импорт кода из той же платформы Target
- Импорт внешних платформ
- Используя Swift от Objective C
- Именование Вашего модуля продукта
- Советы по устранению неисправностей и напоминания
Обзор
Вы можете использовать файлы Objective-C и Swift вместе в одном проекте, независимо от того, какой язык использовался в проекте изначально.
Это делает создание приложений и фреймворков на смешанных языках таким же простым делом, как и создание приложений или фреймворков, написанных на одном языке.
Диаграмма, показывающая шаги по импорту деклараций Objective-C в код Swift. Импортируйте заголовки Objective-C в мостовой заголовочный файл Objective-C, чтобы открыть декларации для всех файлов Swift.
Процесс использования деклараций Objective-C из кода Swift в смешанных языках немного отличается в зависимости от того, пишете ли вы приложение или фреймворк. Оба процесса описаны ниже.
Использование «Swift»-классов в «Objective-C»-файлах
Если вам удалось после импорта «Swift»-заголовка просто использовать какой-либо его класс или метод в «Objective-C»-проекте, вам крупно повезло – значит, кто-то до вас позаботися о совместимности. Дело в том, что «Objective-C» «переваривает» только классы-потомки NSObject и видит только публичные «API». А внутри классов нужные публичные свойства, инициализаторы и методы должны быть аннотированы @objc .
Если мы импортируем свой собственный «Swift»-код, то у нас, конечно, есть возможность в нем и «отнаследоваться» от чего угодно, и аннотацию (или атрибут) @objc добавить. Но в таком случае, наверное, у нас есть возможность и нужный код написать на «Objective-C». Поэтому больший смысл имеет сосредоточиться на случае, когда мы хотим импортировать чужой «Swift»-код в свой проект. В этом случае, скорее всего, у нас нет возможности добавить в нужные классы ни какое-либо наследование, ни прочее. Что делать в таком случае? Остается писать обертки!
Предположим, импортируемый фреймворк содержит следующий нужный нам класс:
Мы создаем свой «Swift»-файл, импортируем в него внешний фреймворк, создаем свой класс, отнаследованный от NSObject , а в нем объявляем приватный член типа внешнего класса. Чтобы иметь возможность вызывать методы внешнего класса, мы определяем методы в нашем классе, которые внутри себя будут вызывать соответствующие методы внешнего класса через приватный член класса (звучит запутанно, но по коду, думаю, все понятно):
(Доступ к классу NSObject и аннотации @objc появляется после импорта Foundation.)
По понятным причинам мы не можем использовать те же имена классов и методов в объявлениях. И здесь нам приходит на помощь аннотация @objc :
Теперь при вызове из «Objective-C»-кода названия классов и методов будут выглядеть именно так, какими мы хотели бы их видеть – как будто мы пишем соответствующие названия из внешнего класса:
Импорт Objective C в Swift
Для импорта ряда файлов Objective C в той же платформе предназначаются как Код SWIFT, необходимо будет импортировать те файлы в заголовок зонтика Objective C для платформы.
Импортировать код Objective C в Swift от той же платформы
При Настройках Сборки, в Упаковке, удостоверяются, что установка Defines Module для той цели платформы установлена в Да.
В Вашем заголовочном файле зонтика импортируйте каждый заголовок Objective C, который Вы хотите представить Swift. Например:
Свифт будет видеть каждый заголовок, который Вы представляете публично в Вашем заголовке зонтика. Содержание файлов Objective C в той платформе будет доступно в любом файле Свифта в той цели платформы автоматически без любых операторов импорта. Используйте свой пользовательский код Objective C с тем же синтаксисом Свифта, который Вы используете с системными классами.
- let myCell = XYZCustomCell ()
- myCell . subtitle = "A custom cell"
Используя Swift от Objective C
Как только Вы импортируете свой Код SWIFT в Objective C, используйте регулярный синтаксис Objective C для работы с классами Swift.
- MySwiftClass * swiftObject = [[ MySwiftClass alloc ] init ];
- [ swiftObject swiftMethod ];
Класс Swift или протокол должны быть отмечены с @objc атрибут, чтобы быть доступным и применимым в Objective C. Этот атрибут говорит компилятору, что к этой части Кода SWIFT можно получить доступ от Objective C. Если Ваш класс Swift является потомком класса Objective C, компилятор автоматически добавляет @objc атрибут для Вас. Для получения дополнительной информации посмотрите Swift Соответствие типов .
У Вас будет доступ к чему-либо в классе или протоколе, это отмечено с @objc припишите, пока это совместимо с Objective C. Это исключает функции только для Swift, такие как перечисленные здесь:
Перечисления определяются в Swift
Структуры определяются в Swift
Функции, определяемые верхнего уровня в Swift
Глобальные переменные определяются в Swift
Typealiases определяется в Swift
Стиль Swift variadics
Функции с приправой карри
Например, метод, берущий универсальный тип в качестве параметра или возвращающий кортеж, не будет применим от Objective C.
Для предотвращения циклических ссылок не импортируйте Swift в заголовочный файл Objective C. Вместо этого можно передать, объявляют, что класс Swift использует его в заголовке Objective C. Обратите внимание на то, что Вы не можете разделить класс Swift на подклассы в Objective C.
Ссылаться на класс Swift в заголовочном файле Objective C
- // MyObjcClass.h
- @class MySwiftClass ;
- @interface MyObjcClass : NSObject
- - ( MySwiftClass * ) returnSwiftObject ;
- /* . */
- @end
Импорт внешних платформ
Можно импортировать внешние платформы, имеющие чистую кодовую базу Objective C, чистую кодовую базу Swift или кодовую базу на разных языках. Процесс для импорта внешней платформы является тем же, записана ли платформа на единственном языке или содержит файлы с обоих языков. То, когда Вы импортируете внешнюю платформу, удостоверьтесь, Определяет установку сборки Модуля для платформы, которую Вы импортируете, установлен в Да.
Можно импортировать платформу в любой файл Swift в различной цели с помощью следующего синтаксиса:
Можно импортировать платформу в любой Objective C .m файл в различной цели с помощью следующего синтаксиса:
Импорт в Objective C
Любая платформа языка
Импорт Swift в Objective C
При импорте Кода SWIFT в Objective C Вы полагаетесь на сгенерированный XCode заголовочный файл для представления тех файлов Objective C. Этот автоматически сгенерированный файл является заголовком Objective C, объявляющим интерфейсы Swift в Вашей цели. Это может считаться заголовком зонтика для Вашего Кода SWIFT. Имя этого заголовка является Вашим именем модуля продукта, сопровождаемым путем добавления "-Swift.h" . (Вы узнаете больше об имени модуля продукта позже в Именовании Вашего Модуля продукта .)
По умолчанию сгенерированный заголовок содержит интерфейсы для объявлений Swift, отмеченных с public модификатор. Это также содержит отмеченных с internal модификатор, если Ваша цель приложения имеет заголовок образования моста Objective C. Объявления, отмеченные с private модификатор не появляется в сгенерированном заголовке. Частные объявления не представлены Objective C, если они явно не отмечены с @IBAction , @IBOutlet , или @objc также. Для получения дополнительной информации о модификаторах уровня доступа посмотрите Управление доступом в Swift Язык программирования.
Вы не должны делать, что-либо специальное для создания сгенерированного заголовочного файла — просто импортирует его для использования его содержания в коде Objective C. Обратите внимание на то, что интерфейсы Swift в сгенерированном заголовке включают ссылки на все типы Objective C, используемые в них. При использовании собственных типов Objective C в Коде SWIFT удостоверьтесь, что импортировали заголовки Objective C для тех типов прежде, чем импортировать сгенерированный заголовок Swift в Objective C .m файл Вы хотите получить доступ к Коду SWIFT от.
Импортировать Код SWIFT в Objective C от той же цели
Импортируйте Код SWIFT из той цели в любой Objective C .m файл в той цели с помощью этого синтаксиса и заменяя надлежащим именем:
Файлы Swift в Вашей цели будут видимы в Objective C .m файлы, содержащие этого оператора импорта. Для получения информации об использовании Swift от кода Objective C посмотрите Используя Swift от Objective C .
Импорт в Objective C
Никакой оператор импорта
Код Objective C
Никакой оператор импорта; заголовок образования моста Objective C требуется
Swift и Objective C в том же проекте
Совместимость Swift с Objective C позволяет Вам создать проект, содержащий файлы, записанные на любом языке. Можно использовать эту функцию, названную смешиванием и подгонкой, для записи приложений, имеющих кодовую базу на разных языках. Используя смешивание и подгонку, можно реализовать часть функциональности приложения, использующей последние функции Swift, и беспрепятственно включить его назад в существующую кодовую базу Objective C.
Советы по устранению неисправностей и напоминания
Обработайте свой Swift и файлы Objective C как тот же набор кода, и не упустите именование коллизий.
Если Вы работаете с платформами, удостоверьтесь, Определяет установку сборки Модуля при Упаковке, установлен в Да.
Если Вы работаете с заголовком образования моста Objective C, удостоверьтесь Objective C, Соединяющий установку сборки Заголовка мостом под Swift Компилятор - Генерация кода имеет путь к заголовку, который это относительно Вашего проекта. Путь должен быть непосредственно к самому файлу, не только к каталогу, в котором это находится.
XCode использует Ваше имя модуля продукта — не Ваше целевое имя — при именовании заголовка образования моста Objective C и сгенерированного заголовка для Кода SWIFT. Для получения информации об именовании модуля продукта посмотрите Именование Вашего Модуля продукта .
Чтобы быть доступным и применимым в Objective C, класс Swift должен быть потомком класса Objective C, или это должно быть отмечено @objc .
При обеспечении Кода SWIFT в Objective C помните, что Objective C не будет в состоянии перевести определенные функции, которые являются определенными для Swift. Для списка посмотрите Используя Swift от Objective C .
При использовании собственных типов Objective C в Коде SWIFT удостоверьтесь, что импортировали заголовки Objective C для тех типов прежде, чем импортировать сгенерированный заголовок Swift в Objective C .m файл Вы хотите использовать свой Код SWIFT от.
Объявления Swift, отмеченные с private модификатор не появляется в сгенерированном заголовке. Частные объявления не представлены Objective C, если они явно не отмечены с @IBAction , @IBOutlet , или @objc также.
Для целей приложения, объявления, отмеченные с internal если цель приложения имеет заголовок образования моста Objective C, модификатор появляется в сгенерированном заголовке.
Для целей платформы, только объявления с public модификатор появляется в сгенерированном заголовке. Можно все еще использовать методы Swift и свойства, отмеченные с internal модификатор из части Objective C Вашей платформы, поскольку долго они объявляются в классе, наследовавшемся от класса Objective C. Для получения дополнительной информации о модификаторах уровня доступа посмотрите Управление доступом в Swift Язык программирования.
Среди самых животрепещущих тем, которые поднимались на наших издательских советах в последние полгода, особое место занимает язык программирования Swift. При огромном интересе к нему со стороны западных разработчиков и при подлинном изобилии книг на эту тему язык пока кажется довольно сырым. Поэтому, прощупывая почву насчет востребованности нового языка, предлагаем познакомиться с постом великолепного Мэтта Нейбурга, автора книги «Programming iOS 8: Dive Deep into Views, View Controllers, and Frameworks». Автор подробно описывает перевод приложения на новый эппловский язык, убедительно доказывая: «глаза боятся — руки делают», а гибридная сборка Objective-C и Swift отнюдь не напоминает смесь французского с нижегородским.
Приятного прочтения и плодотворных экспериментов.
Если у вас уже есть приложение, написанное на языке Objective-C, попробуйте переписать его на Swift. Это отличная возможность познакомиться с языком Swift, поэкспериментировать со Swift и решить для себя, готовы ли вы избрать Swift в качестве своей основной технологии. Я успел выполнить такую миграцию на нескольких реальных приложениях, в этой статье хочу поделиться некоторыми наблюдениями, почерпнутыми на данном опыте.
Гибридные сборки
Разумеется, вам не придется переводить на Swift сразу весь ваш код; гораздо вероятнее, что вы будете переписывать класс за классом. Как только вы добавите файл Swift в сборку вашего приложения, написанного на Objective-C, эта сборка станет гибридной. Некоторые классы в ней останутся на Objective-C, другие будут написаны на Swift. Соответственно, необходимо сделать так, чтобы все объявления были видимы в коде на обоих языках. Прежде, чем приступить к этой работе, давайте разберемся, как функционирует механизм такой видимости.
Как вы помните, объявление класса на языке Objective-C обычно делится на две части: заголовочный файл (.h), содержащий раздел interface, а также файл с кодом (.m), содержащий раздел @implementation. Если в файле .m требуется информация о классе, он импортирует файл .h этого класса.
Взаимная видимость кода Swift и Objective-C основана на следующем соглашении: она обеспечивается на уровне файлов .h. Существует два направления видимости, каждое из них должно быть рассмотрено отдельно.
Как Swift видит Objective-C
Как Objective-C видит Swift
Если у вас есть связующий заголовок, то при создании вашей сборки соответствующие объявления верхнего уровня для всех ваших файлов Swift автоматически переводятся на Objective-C и используются для создания скрытого связующего заголовка в каталоге Intermediates данной целевой сборки, который находится глубоко в папке DerivedData. Этот скрытый заголовок проще всего просмотреть при помощи следующей команды, набираемой в окне терминала:
Так вы узнаете имя скрытого связующего заголовка. В качестве альтернативы попробуйте просмотреть (или изменить) настройку «Product Module Name» в вашей целевой сборке; имя скрытого связующего заголовка создается на основе указанного здесь имени продукта.
Ситуация может значительно измениться от того, где именно в верхней части файла .m импортируется скрытый связующий заголовок. Распространенный тревожный сигнал – появление ошибок компиляции “Unknown type name” (Неизвестное имя типа), где неизвестный тип — это класс, объявленный на языке Objective-C. Чтобы решить эту проблему, нужно импортировать файл .h, содержащий объявление неизвестного типа, и в ваши файлы на Objective-C, причем до импорта скрытого связующего заголовка. Такая работа порой раздражает, особенно если тому файлу Objective-C, о котором идет речь, нет необходимости знать об этом классе, но таким образом мы действительно решаем проблему, после чего компиляция может быть продолжена.
Пошаговые инструкции
Прежде, чем вносить какие-либо изменения, создадим новую ветку в git. Теперь переведем наши классы с Objective-C на Swift, по одному. Я буду делать это по следующему алгоритму:
Не думайте, что обязаны переводить весь код на Swift. Вполне возможно, что некоторые разделы будет лучше оставить на Objective-C, это совершенно нормально. На самом деле, некоторый код необходимо оставить на Objective-C, так как в Cocoa API есть детали, к которым Swift не имеет доступа. Например, нельзя написать на Swift функцию C или указатель на функцию, поэтому вы не сможете вызвать CGPatternCreate или AudioServicesAddSystemSoundCompletion без вспомогательного метода Objective-C. Метод appearanceWhenContainedIn: также нельзя вызвать из Swift.
С другой стороны, код, использующий один из методов performSelector:, которые также недоступны на Swift, можно сразу оставить на Objective-C, но рано или поздно вам придется придумать какой-либо обходной маневр, чтобы эти методы можно было заменить кодом на Swift.
Поэкспериментируем со Swift
Поздравляем! Теперь ваше приложение целиком или частично написано на Swift. Но если вы выполняли все мои рекомендации, то на данном этапе приложение еще не слишком «свифтовское». Ведь мы в первую очередь стремились запустить наш код. Теперь, когда все работает, можно вернуться к самому коду и постараться сделать его более идиоматическим. Возможно, вы обнаружите, что какие-то задачи, которые решались на Objective-C заковыристо или неуклюже, гораздо чище и симпатичнее реализуются на Swift
Разумеется, везде, где только можно, следует перейти на нативные типы Swift. Пары неизменяемых / изменяемых типов, например, NSString и NSMutableString, NSArray и NSMutableArray, а также NSDictionary и NSMutableDictionary можно заменить собственными типами Swift: String, Array и Dictionary. Вы также обнаружите, что более не нуждаетесь в некоторых сложных приемах, которые были сопряжены с этими типами. Так, массив обладает методами экземпляра map, filter и reduce; они вам очень пригодятся.
Например, в одном моем приложении был табличный вид, где выводились данные, разделенные по секциям. На внутрисистемном уровне эти данные записаны в массиве массивов, где каждый подмассив состоит из строк, представляющих собой табличные ряды в той или иной секции. В таблице можно выполнять поиск, и теперь я хочу найти и удалить те строки, в которых отсутствует подстрока, введенная пользователем в поле для поиска. Сами секции я трогать не собираюсь, но если при удалении строк какая-то секция полностью опустеет, то я хочу целиком удалить и весь массив данной секции. Вот как это делалось в Objective-C (sb — это UISearchBar):
Сначала формируем NSPredicate, чтобы отфильтровать массив. Затем циклически перебираем наш массив массивов, “раздавая” компоненты каждого отфильтрованного подмассива в пустой NSMutableArray, один за другим; уверен, вы знакомы с этой идиомой. В Swift же нам не требуется ни NSPredicate, ни идиомы “раздачи” — равно как и двух промежуточных массивов! У нас есть map и filter, вся работа укладывается в единственное утверждение:
Рассмотрим пример.
В моем приложении со словарными карточками у меня есть класс Term, представляющий латинское слово. Он объявляет множество свойств. Каждой карточке соответствует один термин, а каждое из его свойств отображается в отдельном текстовом поле. Когда пользователь нажимает на любое из текстовых полей на экране, я хочу, чтобы актуальный термин в интерфейсе изменился на следующий – отличающийся от предыдущего тем свойством, которое выбрал пользователь. Соответственно, код для всех трех текстовых полей будет одинаковым; вся разница заключается в том, по какому именно свойству мы будем подбирать следующий термин для вывода на экран.
В Objective-C простейший способ выражения такого параллелизма заключался в использовании пар ключ-значение (g — это распознаватель жестов нажатия):
Теперь я могу продолжать использовать пары ключ-значение в Swift; но для этого необходимо, чтобы мой класс Term наследовал от NSObject, а он зависит от динамики Objective-C / Cocoa — перевода строк в имена свойств — чуждой духу Swift. Оказывается, в Swift можно с легкостью реализовать такую же динамику — преобразовав метки в вызовы методов — при помощи простого массива анонимных функций:
Многие свойства Swift нацелены именно на то, чтобы ваш код с самого начала получался более надежным.
Если вы сомневались, стоит ли экспериментировать со Swift – больше не сомневайтесь! Сейчас самое время изучать Swift и смаковать этот язык. В бета-версии среды Xcode 6.3 уже доступна версия Swift 1.2, она позволяет убедиться, что этот язык уже достиг достаточной зрелости. Swift – интересный и простой язык, вы сможете довольно быстро перевести на него любое приложение, которое было написано на Objective-C. Возможно, вы даже удивитесь, насколько яснее и проще окажется получившийся код.
В этой короткой заметке обсудим доступ к классам, объектам и другим объявлениями из кода Objective-C в Swift.
Обращение от редакции: Нашим защитникам из 3-го отдельного батальона УДА, которые находятся в Запорожской области, нужны вещи, чтобы противостоять врагу: квадрокоптеры и смартфоны для управления ими, прицелы ночного видения. Реквизиты для перевода средств на карту monobank – Колонович Катерина, номер карты 5375411505235312. Просим приобщиться к сбору средств. Слава Украине!
Импорт Swift в Objective C
Для импорта ряда файлов Swift в той же платформе предназначаются как код Objective C, Вы ничего не должны импортировать в заголовок зонтика для платформы. Вместо этого импортируйте сгенерированный XCode заголовочный файл для своего Кода SWIFT в любой Objective C .m файл Вы хотите использовать свой Код SWIFT от.
Поскольку сгенерированный заголовок для цели платформы является частью открытого интерфейса платформы, только объявления, отмеченные с public модификатор появляется в сгенерированном заголовке для цели платформы. Можно все еще использовать методы Swift и свойства, отмеченные с internal модификатор из части Objective C Вашей платформы, поскольку долго они объявляются в классе, наследовавшемся от класса Objective C. Для получения дополнительной информации о модификаторах уровня доступа посмотрите Управление доступом в Swift Язык программирования.
Импортировать Код SWIFT в Objective C от той же платформы
При Настройках Сборки, в Упаковке, удостоверяются, что установка Defines Module для той цели платформы установлена в Да.
Импортируйте Код SWIFT из той цели платформы в любой Objective C .m файл в той цели платформы, использующей этот синтаксис и заменяющей надлежащими именами:
Файлы Swift в Вашей цели платформы будут видимы в Objective C .m файлы, содержащие этого оператора импорта. Для получения информации об использовании Swift от кода Objective C посмотрите Используя Swift от Objective C .
Импорт в Objective C
Никакой оператор импорта
Код Objective C
Никакой оператор импорта; заголовок зонтика Objective C требуется
Импорт кода из той же платформы Target
Если Вы пишете платформу на разных языках, Вы, возможно, должны получить доступ к своему коду Objective C от Swift и своему Коду SWIFT от Objective C.
Особенности использования «Swift»-методов в «Objective-C»-файлах
К сожалению, не любые (публичные) «Swift»-методы можно просто пометить @objc и использовать внутри «Objective-C». «Swift» и «Objective-C» – разные языки с разными возможностями и разной логикой, и довольно часто при написании «Swift»-кода мы пользуемся его возможностями, которыми не обладает «Objective-C» или которые реализованы фундаментально по-разному.
Например, от значений параметров по умолчанию придется отказаться. Такой метод:
…внутри «Objective-C»-кода будет выглядеть так:
( 1 – это переданное нами значение, значение по умолчанию у аргумента отсутствует.)
Названия методов
«Objective-C» обладает своей собственной системой, по которой «Swift»-метод будет назван в среде «Objective-C». В большинстве простых случаев, она вполне удовлетворительная, но зачастую требует нашего вмешательства, чтобы стать удобочитаемой. Например, название метода в духе do(thing:) «Objective-C» превратит в doWithThing: , что, возможно, не совпадает с нашим намериением. В этом случае опять-таки приходит на помощь аннотация @objc :
Методы, выбрасывающие исключения
Если «Swift»-метод помечен throws , то «Objective-C» добавит в его сигнатуру еще один параметр – ошибку, которую может выбросить метод. Например:
Использование этого метода будет происходить в духе «Objective-C» (если можно так выразиться):
Использование «Swift»-типов в параметрах и возвращаемых значениях
Если в значениях параметров или возвращаемом значении «Swift»-функции используется не стандартный «Swift»-тип, который не переносится автоматически в среду «Objective-C», этот метод использоваться в среде «Objective-C» опять-таки не выйдет… если над ним не «поколдовать».
Если этот «Swift»-тип является наследником NSObject , то, как упоминалось выше, проблем нет. Но чаще всего оказывается, что это не так. В этом случае, нас снова выручает обертка. Например, исходный «Swift»-код:
Обертка для него:
Использование внутри «Objective-C»:
Импорт Objective C в Swift
Для импорта ряда файлов Objective C в том же приложении предназначаются как Код SWIFT, Вы полагаетесь на заголовок образования моста Objective C для представления тех файлов Swift. Когда Вы добавляете файл Swift к существующему приложению Objective C или файл Objective C к существующему приложению Swift, XCode предлагает создавать этот заголовочный файл.
Если Вы принимаете, XCode создает заголовочный файл вместе с файлом, который Вы создавали, и называет его Вашим именем модуля продукта сопровождаемым путем добавления "-Bridging-Header.h" . (Вы узнаете больше об имени модуля продукта позже в Именовании Вашего Модуля продукта .)
Также можно создать образующий мост заголовок сами путем выбора File> New> File> (iOS или OS X)> Источник> Заголовочный файл.
Необходимо будет отредактировать образующий мост заголовочный файл для представления кода Objective C Коду SWIFT.
Импортировать код Objective C в Swift от той же цели
В Вашем Objective C, соединяющем заголовочный файл мостом, импортируйте каждый заголовок Objective C, который Вы хотите представить Swift. Например:
При Настройках Сборки удостоверьтесь Objective C, Соединяющий установку сборки Заголовка мостом под Swift Компилятор - Генерация кода имеет путь к заголовку.
Путь должен быть относительно Вашего проекта, подобного способу, которым Ваш путь Info.plist указан в Настройках Сборки. В большинстве случаев Вы не должны должны быть изменять эту установку.
Любые общедоступные заголовки Objective C, перечисленные в этом заголовочном файле образования моста, будут видимы к Swift. Функциональность Objective C будет доступна в любом файле Swift в той цели автоматически без любых операторов импорта. Используйте свой пользовательский код Objective C с тем же синтаксисом Swift, который Вы используете с системными классами.
- let myCell = XYZCustomCell ()
- myCell . subtitle = "A custom cell"
Читайте также: