Разработчики часто сталкиваются с типовыми задачами, которые появляются в новых проектах. Постепенно накапливается база вспомогательного кода, которая собирается в библиотеки и переносится из проекта в проект. И чем больше проектов, тем тяжелее становится поддерживать такие библиотеки.

Скорее всего у вас есть излюбленный набор категорий над NSFoundation/UIKit для удобства или что-то для работы с сетью или с пуш уведомлениями. Логично было бы оформить этот код в библиотеку, хранить в одном месте и подключать с помощью пакетного менеджера, например cocoapods. Cocoapods существенно облегчает интеграцию зависимостей в проект. Он все делает за вас, создает нужные таргеты и интегрирует их проект. Такая легкость и простота приводит к тому, что часто встречаются поды, которые состоят только из исходников и примера интеграции. Такой подход рекомендуется официально. И, фактически, этого достаточно для интеграции через cocoapods, но недостаточно для разработки и поддержки. Для этого лучше всего подойдет xcode проект, с помощью которого можно собирать библиотеку.
Xcode проект
Мы назовем нашу тестовую библиотеку Utilities и создадим для нее Xcode проект. Преимущества такого подхода очевидны:
- можно настроить необходимые параметры сборки (
-Wall/-Weverything, iOS7+/iOS8+ итд) и работать над ошибками во время отладки (а не во время интеграции) - можно добавить юнит тесты
- кроме интеграции через cocoapods, есть возможность интеграции через Carthage, вручную или гит сабмодулями.
Static Library vs Framework
При создании проекта необходимо выбрать что мы будем собирать: библиотеку (static library) или фреймворк (dynamic framework). Основное их отличие в том, что фреймворк не совместим с iOS7, а библиотека не поддерживается свифтом.
В нашем случае поддержка iOS7 не нужна, поэтому подойдет фреймворк:

Структура файлов
После создания проекта необходимо изменить структуру файлов в проекте так, чтобы библиотека была совместима с пакетными менеджерами. Самый часто используемый пакетный менеджер это, конечно же, Cocoapods. Остальные используются меньше, но и поддерживать их проще, так как нет необходимости каждый раз после апдейта загружать в хранилище обновленный podspec.
Сocoapods
Для поддержки cocoapods необходимо:
- добавить файл
podspec - добавить файл
LICENSE
В этом вам может помочь команда
pod spec create
Кроме того, если вы не хотите делать библиотеку публичной, нужно создать приватное хранилище пакетов. И добавить в него файл podspec:
pod repo add myrepostorage https://github.com/user/podspecs pod repo push myrepostorage Utilities.podspec
Пример файла podspec:
Pod::Spec.new do |s| s.name = "Utilities" s.version = "0.0.1" s.summary = "My test library" s.homepage = "https://github.com/user/utilities" s.authors = "author name" s.license = "MIT" s.platform = :ios, "8.0" s.source = { :git => "https://github.com/user/utilities.git", :tag => "#{s.version}" } s.source_files = "Sources/**/*" end
Swift Package Manager
Для поддержки Swift PM необходимо:
- положить исходники в папку
Sources - добавить файл
Package.swift
Пример Package.swift:
import PackageDescription let package = Package( name: "Utilities" )
Carthage
Для поддержки carthage необходимо чтобы:
- файл проекта
xcodeprojнаходился в корневой папке - схема в проекте была отмечена как shared

Кроме того не помешает:
- добавить описание в
README.mdдля гитхаба - положить юнит тесты в папку
Tests - положить вспомогательные файлы в папку
Supporting Files
В результате должна получиться следующая структура:

В папке Supporting Files лежит файл Defaults.xcconfig, который применяет настройки компиляции к проекту. Его удобно положить во все подобные библиотеки, чтобы не настраивать все руками. У нас есть желание сделать строгие настройки, чтобы код был лучше, например такие:
CLANG_WARN_ENUM_CONVERSION = YES CLANG_WARN_INT_CONVERSION = YES CLANG_WARN_CONSTANT_CONVERSION = YES CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_ASSIGN_ENUM = YES CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES CLANG_WARN_IMPLICIT_SIGN_CONVERSION = YES CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES CLANG_ANALYZER_SECURITY_INSECUREAPI_RAND = YES GCC_WARN_CHECK_SWITCH_STATEMENTS = YES GCC_WARN_64_TO_32_BIT_CONVERSION = YES GCC_WARN_ABOUT_MISSING_NEWLINE = YES GCC_WARN_SHADOW = YES GCC_WARN_SIGN_COMPARE = YES GCC_TREAT_WARNINGS_AS_ERRORS = YES WARNING_CFLAGS = -Weverything -Wno-objc-missing-property-synthesis -Wno-gnu -Wno-float-equal -Wno-nullable-to-nonnull-conversion -Wno-auto-import -Wno-direct-ivar-access
Зависимости
Если библиотека имеет зависимость, например от AFNetworking, то интегрировать эту зависимость можно как обычно, привычными методами. Например, с помощью cocoapods или carthage ее можно подключить к нашей библиотеке. Ещё нужно не забыть указать эту зависимость в соответствующих файлах конфигурации для пакетных менеджеров. Для cocoapods это Podfile, а для carhage это Cartfile.
Итог
В результате получаем библиотеку, которую легко поддерживать и интегрировать с помощью любого пакетного менеджера.

