Несколько фреймворков и общая библиотека

Использование iOS 8, Xcode 6.

Допустим, у меня есть 2 динамических фреймворка, frameworkA и frameworkB, и оба они зависят от libC. Кроме того, у меня есть приложение, которое использует как frameworkA, так и frameworkB. Моя первоначальная мысль заключалась в том, чтобы сделать frameworkA и frameworkB зонтичными фреймворками и libC подфреймворком. Однако Apple не рекомендует использовать зонтичную инфраструктуру, и в этом сообщении описывается, почему зонтичная инфраструктура - плохая идея из-за потенциальной проблемы конфликта компоновщика.

Мой второй вариант — использовать Cocopods (все еще новичок в этом, поэтому немного нечетко в деталях), чтобы использовать libC в качестве модуля, который затем компилируется в frameworkA и frameworkB. Однако мне пришло в голову, что у обоих фреймворков все еще есть собственная копия файла libC. Поскольку приложение использует обе платформы, не приведет ли это к конфликту компоновщика? Есть ли лучший способ решить эту проблему?

ОБНОВЛЕНИЕ @Rob Проекты, над которыми я работаю, требуют сложного управления зависимостями, но я оставил проблемную область простой в вопросе, чтобы попытаться лучше понять, как и может ли использование Cocopods помочь решить проблему конфликта компоновщика с зонтичными фреймворками. . Я работаю с командой разработчиков, которые пишут библиотеки и могут полагаться на базовые библиотеки друг друга, предоставляющие стандартные версии API. Мы должны упаковать и доставить как можно меньше библиотек другой организации, которая создает приложение с нашими библиотеками, и одним из их ключевых требований является то, что мы предоставляем динамическую структуру.


person Bob    schedule 31.01.2015    source источник


Ответы (1)


Лучший способ решить большинство проблем — поместить весь код в проект и скомпилировать его. Если у вас есть специализированные проблемы, которые делают это проблематичным, вам следует рассмотреть другие решения, такие как статические библиотеки и, наконец, фреймворки.

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

Если вы продаете библиотеки с закрытым исходным кодом, то фреймворки очень привлекательны. Вам следует настоятельно избегать добавления сторонних зависимостей по отмеченным вами причинам. Если вам нужно, лучший способ — помочь вашим клиентам упаковать все части в виде фреймворков и попросить их связать все в конце. Но это добавляет много раздражения; поэтому убедитесь, что вам действительно нужна эта сторонняя часть.

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

(Кстати, это не новое решение. Когда вы используете curl, если вам нужен SSL, вам также необходимо загрузить и собрать OpenSSL и связать их вместе самостоятельно. Curl не поставляется со встроенным OpenSSL.)

Но в подавляющем большинстве случаев все это перебор. Не прыгайте на фреймворки. Не прыгайте в библиотеки. Просто поместите весь код в проект и скомпилируйте его. 90% ваших проблем испарятся. В частности, проекты iOS обычно не такие уж большие. Какую проблему решает фреймворк?

Если у вас есть много кода, который ваша организация постоянно использует во многих продуктах, то я слышал, что многие команды успешно используют внутренние CocoaPods для управления этим. Но это просто для упрощения проверки кода. Все это по-прежнему входит в проект, и вы компилируете его вместе в один двоичный файл; рамки не нужны. Динамические фреймворки — это хорошая возможность для определенных видов проблем, которые раньше были очень болезненными. Но в большинстве ситуаций они просто усложняют поиск проблемы.

(Если у вас есть одна из этих специализированных проблем, отредактируйте свой вопрос, и я буду рад обсудить, как вы можете к ней подойти.)


РЕДАКТИРОВАТЬ: (Вы попадаете в эту «специализированную проблему», так что давайте поговорим об этом. Я тоже много лет работал в большой многокомандной среде разработки Mac и iOS. И мы пробовали практически все различные решения, включая Frameworks , Они только новые на iOS.)

В организации, которую вы описываете, я бы настоятельно рекомендовал упаковать каждую зависимость как свою собственную структуру (AFNetworking, JSONKit и т. д.) и каждую из ваших частей как структуру, а затем заставить разработчиков приложения связать их все вместе в конце. Таким образом, он идентичен другим динамическим библиотекам (libcurl, openssl и т. д.), которые требуют, чтобы разработчик приложения связывал все вместе.

Ни в коем случае динамические фреймворки не должны включать в себя другие фреймворки, которые в противном случае могли бы потребоваться (т. е. фреймворки никогда не должны упаковывать «сторонний» материал). Это взорвется. Вы не можете заставить это не взорваться. У вас будет либо раздувание, либо конфликты сборки, либо конфликты во время выполнения. Это похоже на конфликты слияния. Есть момент, когда разработчик должен сделать выбор. Связывание на уровне приложения делает этот выбор.

Чрезмерная зависимость компонентов от других компонентов является источником проблем десятилетиями, от Windows DLL Hell до приложений iOS с конкурирующими обработчиками сбоев. Все лучшие системы компонентов выглядят как лего, где конечный пользователь собирает небольшие детали, которые имеют минимальные зависимости. Насколько это возможно, сделайте так, чтобы ваши внутренние фреймворки полагались только на Cocoa. Это оказывает ощутимое влияние на дизайн:

  • Избегайте прямого требования ведения журналов или аналитических механизмов. Предоставьте интерфейс делегата, который можно адаптировать к механизмам вызывающего объекта.
  • Избегайте тривиальных категорий (методов, которые экономят всего несколько строк кода). Просто напишите код напрямую.
  • Избегайте добавления зависимостей фреймворка, которые не принесут вам много пользы. Не добавляйте AFNetworking только для того, чтобы сохранить несколько строк кода поверх NSURLConnection. Конечно, если вы сильно полагаетесь на функции другого фреймворка, это другое дело. Но как разработчик фреймворка ваш порог должен быть достаточно высоким, прежде чем вам потребуется другой фреймворк.
  • Настоятельно избегайте быть умным в сборке или контроле версий. Я видел слишком много случаев, когда люди хотят сделать все «автоматическим» для разработчика на уровне приложения и таким образом сделать систему действительно сложной. Просто скажите: «Вам нужно связать это, импортировать это и поместить это в запуск делегата вашего приложения». Не создавайте сложные системы сборки и контроля версий, чтобы сэкономить 2 минуты на первой сборке или две строки логики инициализации. Эти вещи взрываются и тратят часы на работу. Не умничайте с +load магией. Просто сделайте это ясным и последовательным.

И, конечно же, удачи. Поддержка других разработчиков всегда интересная задача.

person Rob Napier    schedule 31.01.2015
comment
обновлено. да, вы один из тех особых случаев, которые я обсуждал. :D - person Rob Napier; 31.01.2015
comment
Кроме того, знаете ли вы, решит ли описанное использованиеcocopods проблему конфликта компоновщика? - person Bob; 01.02.2015
comment
Да, но в основном избегая фреймворков (я полагаю, что CP сейчас исследует фреймворки, но это вернет проблему). В типичной настройке CP он обрабатывает все зависимости, извлекает их, а затем компилирует все вместе. Это то же самое, что я рекомендую, только немного более автоматический (с компромиссом работы с более сложным рабочим пространством CP). Однако CP может усложнить обеспечение воспроизводимых сборок, поскольку он побуждает вас получать последнюю, а не какую-то конкретную версию. После извлечения вещей вы должны проверить их в системе контроля версий. - person Rob Napier; 01.02.2015
comment
Лично я не использую CP очень часто. Большая часть моего опыта с ним связана с общением с консультантами, которых я знаю, которые используют его для поддержки своего внутреннего общего кода, как вы обсуждаете. - person Rob Napier; 01.02.2015
comment
Что ж, поставка каждой библиотеки в виде фреймворка невозможна из-за внутренних требований заказчика. CP позволяет мне указывать конкретные версии, и я по-прежнему буду предоставлять несколько фреймворков, но не несколько зонтичных фреймворков. Дайте мне знать, если вы знаете о других проблемах. - person Bob; 02.02.2015