Теперь, поскольку мы немного разобрались в разнице между типами связываний, давайте подумаем почему наше приложение может тормозить при старте и на что фактически уходит это время. Для того чтобы это понять, нам необходимо разобраться в том, как работает динамическое связывание.
Когда пользователь нажимает на иконку приложения на устройстве, система заменяет текущий процессией только что созданным и передает ему управление.
Ваше приложение загружается в память устройства, где-то на этом этапе производится ASLR и система подгружает утилиту dylib, которая начинает загружать библиотеки в память.
Алгоритм загрузки зависимостей давольно простой - это обычный DFS. Загрузка библиотеки в память происходит после того, как загружены все прямые и транзитивные зависимости этой библиотеки.
Как только все библиотеки загружены, управление передается приложению, через вызов функции main и ваш AppDelegate получает вызов соответствующего метода.
Так на что же тратится время? В основном, весь процесс замедляется за счет безопастности. Помимо применения ASLR, дополнительная безопасность вашего приложения и всех его компонент осуществляется при помощи сверки подписи.
dylib не может загружать в память какие угодно библиотеки, для каждой загружаемой зависимости, необходимо сверить подпись и подтвердить, что она была выпущена либо разработчиком приложения, либо Apple.
Как раз эта проверка и съедает львиную часть драгоценного времени при запуске вашего проекта.
Вы можете пересмотреть необходимость использования динамической связки. В большинстве случаев, ваши зависимости будут необходимы только в основном исполняемом файле.
Для смены типа связывания ваших внутренних тагретов,смените тип связки на MACH_O_TYPE = staticlib, в настройках проекта.
Будьте внимательны при работе с ресурсами. Так как статический фреймворк не копируется в бандл приложения, ресурсы содержащиеся в этом фреймворке туда тоже не попадут.
Создайте отдельный таргет в вашем проекте с MACH_O_TYPE = mh_bundle и поместите туда все свои картинки, xib файлы и прочие ресурсы. Затем укажите его в фазе Copy Bundle Resources вашего приложения. Теперь этот бандл будет лежать рядом с исполняемым файлом вашего проекта.
Осталось задать новый путь к ресурсам, при помощи указания пути относительно основного бандла
let resourcePath = Bundle.main.path(forResource: "MyBundle", ofType: "bundle")
Теперь вы можете использовать ресурсы вместе со статическими библиотеками!
Из опыта работы в такой молодой и успешной компании, трюк с изменением типа связки помог увеличить количество клиентов приложения на 30%
Как оказалось, время запуска приложения играет огромную роль в при вызове такси, заказе еды или оплате услуг. У кого приложение быстрее, того и любят больше