Ответ
Размер Swift-приложения может быть больше аналогичного на Objective-C из-за особенностей компиляции и безопасности языка.
Основные причины:
-
Библиотека времени выполнения (Swift Runtime):
- Не является частью ОС (в отличие от Objective-C runtime).
- Включается в бинарник приложения, добавляя ~2-5 МБ.
-
Генерики (Generics) и специализация:
- Компилятор создает отдельную реализацию для каждой комбинации типов, используемых с дженериком.
// Для Int и String будут сгенерированы две разные функции func process<T>(_ value: T) { ... } process(10) // Специализация для Int process("text") // Специализация для String
- Компилятор создает отдельную реализацию для каждой комбинации типов, используемых с дженериком.
-
Код для гарантий безопасности:
- Проверки границ массивов, переполнения целых чисел, обработка опционалов — весь этот код добавляется в бинарник.
-
Отладочные сборки (
-Onone):- Содержат символы для отладки и минимальную оптимизацию, что сильно увеличивает размер.
Способы оптимизации размера:
- Release-оптимизация: Используйте
-Osize(оптимизация по размеру) вместо-O(по скорости). - Удаление неиспользуемого кода: Включите
DEAD_CODE_STRIPPING = YESиSTRIP_STYLE = ALL. - Использование App Thinning: (Bitcode, Slicing) для доставки оптимизированного бинарника под каждое устройство.
- Минимизация динамических фреймворков: Статическая линковка может уменьшить итоговый размер.
Ответ 18+ 🔞
Ну вот, опять про размер приложений заговорили. Смотри, объясняю на пальцах, почему твой Swift-код весит как здоровенный кирпич, а старый добрый Objective-C — как перышко.
Первое и главное — Swift Runtime. Это такая штука, без которой твой Swift-код — просто набор красивых букв. И знаешь, где она живёт? Правильно, в твоём бинарнике, ёпта! В iOS она не вшита в систему, как для Objective-C. Так что готовься отдать лишних 2-5 мегабайт просто за право сказать, что пишешь на модном языке. Ядрёна вошь!
Дальше — генерики. О, это моя любимая песня! Ты думаешь, написал одну умную функцию — и всё, красота? А вот хуй там! Компилятор-то не дурак, он для каждого типа, которым ты воспользуешься, сделает свою отдельную копию. Смотри:
func process<T>(_ value: T) { ... }
process(10) // Тут он сгенерирует функцию для Int
process("text") // А тут уже совсем другую — для String
И так по кругу. Наиспользуешься этих дженериков — и получишь бинарник размером с хороший роман Толстого, блядь.
Третье — безопасность. А ты как думал? За все эти красивые опционалы, за то, что массив сам тебя по рукам бьёт, если за границы полез, — надо платить! Весь этот охранный код, проверки, страховки — всё это компилятор аккуратненько вставляет в твоё приложение. Хочешь жить без сюрпризов? Плати мегабайтами, чувак.
И наконец, если ты собираешь отладочную сборку (-Onone), то вообще пиши пропало. Там и символы отладочные на каждый чих, и оптимизации никакой. Приложение раздувается, как мыльный пузырь.
Так что делать-то, как не околеть с жиру?
- Собирай на релиз правильно. Не просто
-O(оптимизация по скорости), а-Osize— чтобы компилятор старался не разогнать код, а ужать его по максимуму. - Выкидывай мусор. В настройках проекта включи
DEAD_CODE_STRIPPING = YESиSTRIP_STYLE = ALL. Пусть линкер вырежет всё, до чего ты ни разу не дотронулся. - Пользуйся App Thinning. Bitcode, Slicing — это не просто слова для красоты. Это чтобы в App Store каждому устройству прилетал только нужный кусок бинарника, а не целый воз с сеном.
- С динамическими фреймворками аккуратней. Иногда статическая линковка может помочь размер уменьшить, потому что линкуется только то, что реально используется, а не вся библиотека целиком.
Вот и весь сказ. Хочешь безопасность и современный синтаксис — будь добр, тащи на себе Swift Runtime и все его защитные механизмы. Волшебства не бывает. Чих-пых тебя в сраку!