Как сделать универсальную библиотеку iOS для Objective-C и Swift?

Мне нужно сделать библиотеку для iOS (либо Framework, либо статическую библиотеку - я еще не решил), которую можно использовать как в проектах Objective-C, так и в проектах Swift. Как лучше всего это сделать? Как я это вижу, у меня есть три варианта:

  1. Напишите библиотеку на Objective-C и добавьте поддержку Swift (связывание заголовков и т. д.).
  2. Напишите библиотеку на Swift и добавьте поддержку Objective-C.
  3. Напишите две библиотеки, как на Objective-C, так и на Swift. Я очень хочу избежать этого варианта.

Главное требование здесь заключается в том, чтобы разработчикам было как можно проще пользоваться им. В идеале они должны иметь возможность выбирать свой язык и не заботиться или даже знать, на каком языке написана сама библиотека. Можно ли это сделать?

Кроме того, я хочу иметь возможность распространять библиотеку с помощью CocoaPods, если это имеет какое-либо значение.


person pajevic    schedule 14.04.2016    source источник
comment
вариант 1, скорее всего, поскольку по мере перехода от версии к версии пользователям вашей библиотеки придется ждать перед обновлением, если они полагаются на вашу библиотеку   -  person Fonix    schedule 14.04.2016
comment
Спасибо за отзыв, Fonix. Я даже не рассматривал это.   -  person pajevic    schedule 14.04.2016


Ответы (1)


Вариант 2. Не может быть и речи (подробно описан ниже)
Вариант 3. Как вы сказали, его действительно следует избегать.

Вариант 1 лучше всего. Просто разработайте свой API с учетом Obj-C и Swift. Что это означает ?

• Не используйте селекторы – это не стандарт Swift.
Используйте возможность обнуления. для преобразования в необязательные
• Замыкания и блоки могут иметь одинаковый синтаксис, но есть небольшая разница, обратите внимание на это:

Замыкания Swift и блоки Objective-C совместимы, поэтому вы можете передавать замыкания Swift в методы Objective-C, которые ожидают блоков. Замыкания и функции Swift имеют один и тот же тип, поэтому вы даже можете передать имя функции Swift.

Замыкания имеют семантику захвата, схожую с блоками, но отличаются одним ключевым моментом: переменные изменяются, а не копируются. Другими словами, поведение __block в Objective-C является поведением по умолчанию для переменных в Swift.

Источник: Apple Использование Swift с Cocoa и Objective-C — это объясняет все в деталях.

Вы можете прочитать больше здесь.

При разработке такого API вы должны знать, как все конвертируется, но если вы сделаете это правильно, пользователи не заметят разницы :)

Файл модуля

Убедитесь, что ваш x.framework поставляется с папкой modules и файлом внутри.

Новый Xcode генерирует его для вас. Таким образом, пользователи могут использовать ваш проект Obj-C в Swift, не добавляя его в файл моста. Так что они могут просто import myLib из коробки.

введите здесь описание изображения

Почему не Свифт?


К сожалению, сейчас самый разумный способ распространять скомпилированную библиотеку — писать ее на Objective-C.

И это из-за одной важной причины: Проблема совместимости двоичных файлов Swift

В то время как совместимость вашего приложения во время выполнения обеспечивается, сам язык Swift будет продолжать развиваться, и бинарный интерфейс также будет меняться. В целях безопасности все компоненты вашего приложения должны быть созданы с использованием одной и той же версии Xcode и компилятора Swift, чтобы обеспечить их совместную работу.

Это означает, что фреймворками необходимо тщательно управлять. Например, если в вашем проекте используются фреймворки для совместного использования кода со встроенным расширением, вы захотите создать фреймворки, приложение и расширения вместе. Было бы опасно полагаться на бинарные фреймворки, использующие Swift, особенно от третьих лиц. По мере изменения Swift эти фреймворки будут несовместимы с остальной частью вашего приложения. Когда через год или два бинарный интерфейс стабилизируется, среда выполнения Swift станет частью основной ОС, и это ограничение больше не будет существовать.

Питер Стейнбергер, основатель PSPDFKit, который также является библиотекой, распространяемой в виде скомпилированной библиотеки, столкнулся с той же проблемой: они пока застряли на Obj-C и не могут использовать Swift.

person michal.ciurus    schedule 14.04.2016
comment
Спасибо за ответ. Лично у меня пока нет большой проблемы с необходимостью придерживаться Objective-C. Моя единственная забота здесь - как упаковать библиотеку таким образом, чтобы разработчикам Swift не приходилось беспокоиться о Objective-C. - person pajevic; 14.04.2016
comment
Отличные моменты, Майкл, спасибо за это. Итак, есть ли что-то конкретное, что мне нужно сделать при упаковке моего фреймворка. Как сделать так, чтобы его можно было использовать со Swift из коробки? - person pajevic; 14.04.2016
comment
Отредактировал мой ответ. Вам не нужно ничего делать, кроме как убедиться, что у вас есть новый Xcode: D - person michal.ciurus; 14.04.2016
comment
Комментарии по поводу модуля излишни при распространении через CocoaPods. Это библиотека Objective-C, которая отлично работает из Swift, загруженного через CocoaPods. - person nhgrif; 14.04.2016
comment
Это относится к скомпилированному .framework, распространяемому с CocoaPods? Я так не думаю. Обратите внимание, что библиотека, на которую вы ссылаетесь, является открытым исходным кодом. Это другое. - person michal.ciurus; 14.04.2016
comment
В целом, я думаю, самое важное замечание здесь заключается в том, что библиотеки Objective-C отлично работают из Swift без каких-либо дополнительных усилий, хотя вам определенно следует приложить дополнительные усилия, чтобы добавить аннотации обнуляемости и указать общие типы в ваших коллекциях. Даже когда мы получим более стабильную версию Swift, используя Swift, мы можем отрезать потенциальных пользователей библиотеки, которые, например, все еще пытаются поддерживать iOS 6. - person nhgrif; 14.04.2016
comment
@michael Могу я побеспокоить вас дополнительным вопросом? В своем ответе вы пишете Не используйте селекторы - они не являются стандартом Swift - что именно это означает? Я спрашиваю, потому что в моей структуре у меня есть протокол делегата с необязательными методами. Обычно я бы использовал метод respondsToSelector: с параметром @selector(), чтобы проверить, был ли метод реализован в делегате, но мне не разрешено делать это, если я хочу, чтобы он был безопасным для Swift. Или это относится только к методам публичной библиотеки? - person pajevic; 05.05.2016
comment
Конечно. Это очень просто: селекторы — это не Swift. Это объективный механизм. Более того, он не работает с чистыми классами Swift, если только вы не используете свойство @objc. Подробнее здесь: stackoverflow.com/questions/24007650/selector-in-swift - person michal.ciurus; 05.05.2016
comment
Спасибо Михал. Однако я уже видел этот пост, и он мне не очень помогает. Это касается того, как вы обрабатываете сценарии на основе селекторов в Swift, но мне нужно знать, что делать в моей библиотеке Objective-C, чтобы она также работала для людей, использующих Swift. Должен ли я вообще избегать использования селекторов? - person pajevic; 06.05.2016
comment
Да, вам нужно избегать использования селекторов, как я написал в ответе. Селекторы не могут быть преобразованы в какой-либо стандарт Swift, например, nulability. - person michal.ciurus; 06.05.2016
comment
@michal.ciurus Вы уверены, что правы? :) На самом деле я протестировал свою структуру в приложении Swift и не обнаружил проблем, хотя я использую respondsToSelector: и @selector(). Я думаю, что мы можем использовать селекторы внутри во фреймворке. - person pajevic; 07.05.2016
comment
Да, использовать его внутрь нормально. Вы не должны использовать его в общедоступном API. - person michal.ciurus; 07.05.2016
comment
Swift теперь имеет стабильность ABI. Не могли бы вы обновить свой ответ, я уверен, что у вас будет много замечательных идей. Спасибо! :) - person Ben Butterworth; 06.06.2021