iOS Dev
7.7K subscribers
996 photos
82 videos
1 file
1.15K links
🍏Канал об iOS-разработке, необычных подходах и решениях.
👨‍💻Автор: Виктор Грушевский (@Viktorianec)
Темы:
⭐️ Подготовка к собеседованиям.
⭐️ Архитектуры и алгоритмы.
⭐️ Код. Много кода.

⚒️База знаний: https://boosty.to/ios_dev

#ios #mobile #swift
Download Telegram
Объяснение взаимоблокировок (deadlocks) в Swift: обнаружение проблем и их способы их решения

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

В таких ситуациях приложение перестает отвечать на запросы, а единственно возможным решением кажется перезапуск приложения.

Хотя такие функции, как акторы, уменьшают количество потенциальных дэдлоков, с которыми вы столкнетесь, вероятность их появления по-прежнему высока.

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

📖 Антуан Ван Дер Ли с помощью своего 10-летнего опыта рассказал о причинах взаимоблокировок и поделился, как можно сузить радиус поиска.

@iOS Dev
UILabel стоит больше, чем вы думаете

Мы склонны считать лейблы легкими с точки зрения использования памяти. В конце концов, они просто отображают текст.

UILabels на самом деле хранятся в виде растровых изображений, которые легко могут потреблять мегабайты памяти.

К счастью, реализация UILabel умна и потребляет только то, что ей нужно:

🔘 Если ваш лейбл монохромен, UILabel выберет CALayerContentsFormat из kCAContentsFormatGray8Uint (1 байт на пиксель).
Но на немонохромные лейблы, например, для отображения «😰пожалуйста, попытайтесь сохранить душевное спокойствие, насколько можете» или многоцветные NSAttributedString, потребуется использовать kCAContentsFormatRGBA8Uint (4 байта на пиксель).

Монохромный лейбл потребляет не более width * height * contentsScale ^2 * (1 byte per pixel), а немонохромный — в 4 раза больше: width * height * contentsScale ^2 * (4 byte per pixel).

🔘 Например, на iPhone 11 Pro Max лейбл размером 414 * 100 точек может потреблять до: 414 * 100 * 3 ^ 2 * 1 = 372,6 КБ, а немонохромный 414 * 100 * 3 ^ 2 * 4 = ~ 1,49 МБ.

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

В распространенном анти-паттерне лейблы ячеек UITableView/UICollectionView остаются заполненными их текстовым содержимым, когда эти ячейки попадают в reuse queue.

Весьма вероятно, что после повторного использования ячеек текстовое значение меток будет другим, поэтому их хранение расточительно.

✅️ Несложные советы, которые помогут освободить потенциально мегабайты памяти:

1️⃣ Обнуляйте текст лейблов, если вы сделаете их скрытыми и будете отображать только изредка.

2️⃣ Обнуляйте текст лейблов, если они отображаются в ячейках UITableView/UICollectionView, в didEndDisplaying:forItemAt:

📖 В этом материале есть ещё несколько советов, которые помогут вам улучшить производительность.

📖 А вот тут можно прочесть про изображения и пути оптимизации.

@iOS Dev
Please open Telegram to view this post
VIEW IN TELEGRAM
30 советов, которые можно добавить в набор инструментов iOS-разработчика

📖 Rony Fadel делится своим опытом, рассказывая и о фишках Xcode, и о том, что можно применить в вашем коде уже в следующем проекте.

@iOS Dev
Новый способ для работы со временем в iOS 16

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

🕔 Расчеты с использованием Duration могут применяться как для точности до долей секунды, так и для измерений, охватывающих столетия.

1️⃣ Пример с добавлением миллисекунд.

var d: Duration = .seconds(3)
d += .milliseconds(33)
print(d) // 3.033 seconds



2️⃣ Пример с форматированием в часы и минуты.

let timeRemaining: Duration = .seconds(6900)

// 01:55
let padHourToLength2 = timeRemaining.formatted(
.time(pattern: .hourMinute(padHourToLength: 2))
)


📖 А о других API для взаимодействия со временем можно прочесть в этом посте.

@iOS Dev
Динамическое создание PDF-файлов с использованием PDFKit в Swift

Динамическое создание отчетов в формате PDF может быть чрезвычайно полезным при разработке приложений Swift.

Пользователи смогут создавать персонализированные файлы, которые они смогут очень легко экспортировать.

📖 В этом материале автор делится своим опытом и рассказывает о том, как:

🔘 Сгенерировать PDF-документ.
🔘 Показать свои данные в заданном стиле.
🔘 Отформатировать текст на примерах (шрифт, размер, подчеркивание, и так далее).
🔘 Перейти на новую страницу при необходимости.
🔘 Пошарить сгенеренный PDF.

👨‍💻 Код из статьи — по этой ссылке.

@iOS Dev
Please open Telegram to view this post
VIEW IN TELEGRAM
Starly + App Store Connect SDK = ProductHunt

📱Новый App Store Connect API можно использовать для получения метаданных приложений, сборок TestFlight, загрузки отчетов о продажах и многого другого.

App Store Connect API соответствует спецификациям OpenAPI и поставляется с богатой документацией от Apple.

Недавно Antoine v.d. SwiftLee (автор одноимённого сайта и рассылки с обучающими материалами) выкатил новое SDK для работы с апи аппстора.

📖 Почитать о принципах работы SDK можно в этом материале.

На протяжении некоторого времени я изучал возможности SDK, и в твиттере смог решить с Антуаном интересующие меня вопросы.

🎉 В итоге появилось приложение Starly, с помощью которого можно отвечать на отзывы в аппсторе (а ещё переводить их и добавлять шаблоны ответов, и шарить лучшие из них), на данный момент не имеющее ни одного аналога, за исключением стандартного приложения.

💻 Приложение доступно на macOS, iPhone и iPad.

Я запустил его также на продактханте и впервые прошу вашей помощи:

🟢 Если вы зарегистрированы на ProductHunt, то, пожалуйста: поддержите приложение на портале.

🟢 Или, если вам понравилась идея — установите его и напишите в отзывах, что можно улучшить.

@iOS Dev — я рассчитываю на вашу поддержку.
This media is not supported in your browser
VIEW IN TELEGRAM
Реализация превью в реальном времени для UIViewController

Одной из лучших функций SwiftUI является возможность предварительного просмотра вашего кода во время разработки, но знаете ли вы, что вы также можете использовать SwiftUI для предварительного просмотра ваших старых UIViewControllers и UIView?

📖 И, скорее всего, вы догадались, что в этой статье автор расскажет про то, как использовать протокол UIViewControllerRepresentable, который позволяет создавать и управлять UIViewController из SwiftUI.

@iOS Dev
Как тестировать приложения для iOS, используя имитацию данных

ℹ️ Чтобы предоставлять высококачественное программное обеспечение и избегать регрессии, внедрение модульного тестирования является обязательным для каждого приложения iOS.

Имитация объектов (или использование моков) — это метод модульного тестирования, который создает поддельные объекты с использованием тех же API, что и настоящие.

📕 В этой статье автор рассказывает о рекомендациях по использованию таких данных и написанию модульных тестов для наиболее часто встречающихся сценариев в приложениях для iOS.

@iOS Dev
Please open Telegram to view this post
VIEW IN TELEGRAM
BackgroundTask в SwiftUI: примеры коды и способы тестирования

Apple выпустила API под названием BackgroundTask для актуализации контента вашего приложения и выполнения операций, которые займут несколько минут, пока оно работает в фоновом режиме.

Следует учитывать, что для выполнения более длительных задач этому API может потребоваться включенное устройство и подключение к сети.

Вы указываете, что задача должна выполняться время от времени, а система решает, соответствует ли это активности пользователя.

Вы никогда не должны полагаться на такое планирование для чего-то критически важного для вашего приложения.

Также важно уточнить, что приложение может запланировать только 1 задачу обновления за раз и 10 задач обработки, запланированных в любое время, как сказано в документе.

📖 В этом материале рассказывается о реализации, а также о необходимом подготовительном этапе.

📖 Важное руководство по работе в фоновом режиме.

ℹ️ В Xcode 14.0 был баг в определённых условиях, но согласно этому треду он исправлен в Xcode 14.1 (впрочем, ничего нового).

@iOS Dev
Парсинг JSON в Swift: объяснение с примерами кода
Статья рассчитана на новичков, которым полезно начать с базы для разбора основных принципов

🤔 Парсинг JSON в Swift — обычное дело, встречающееся едва ли не в каждом втором (а может и в в каждом) проекте.

В целом, декодирование JSON в Swift довольно простое и не требует никаких внешних зависимостей.

📖 Базовых API, поставляемых со Swift, будет достаточно для выполнения этой работы, а в этом материале рассказывается о следующих понятиях:

1️⃣ Основы декодирования JSON.

2️⃣ Декодирование JSON-массивов в Swift.

3️⃣ Сопоставление ключей (или же маппинг) JSON с кастомными свойствами.

4️⃣ Декодирование дат JSON с кастомными форматами (например, датой, включая возможные стратегии).

@iOS Dev
Please open Telegram to view this post
VIEW IN TELEGRAM
Время очередной интересной истории
Попробую вас удивить, а вы постарайтесь догадаться, о чём идёт речь

1️⃣ Этот символ появляется на ряде древних предметов в Северной Европе.

2️⃣ Он занимает видное место на картинном камне из Хаблингбо в Швеции, который был создан между 400 и 600 годами нашей эры.

3️⃣ Он также похож на традиционную геральдическую эмблему, называемую узлом Боуэна.

4️⃣ В Финляндии этот символ рисовали или вырезали на домах и амбарах, а также на домашней утвари, такой как посуда, чтобы защитить их и их владельцев от злых духов и неудач.

5️⃣ Самый старый сохранившийся пример — пара деревянных лыж возрастом 1000 лет (финский дохристианский период), украшенных этим символом.

🤔 Всё ещё не догадались, о чём я веду речь?

Этот символ также появляется на артефактах культуры Миссисипи на юго-востоке Соединенных Штатов.

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

📕 Всё ещё нет?

Английские названия Saint John's Arms, Saint Hannes cross или Saint Hannes's Cross, а также скандинавские названия относятся к Иоанну Крестителю.

Все эти подсказки, и вся информация об этом должны были навести вас на мысль, что я рассказывал о:

Компьютеры Apple вплоть до Apple II Plus 1979 года не имели командной клавиши. А вся информация ведёт к тому, что Символ ⌘ («квадрат с петлей») был выбран Susan Kare после того, как Стив Джобс решил, что использование логотипа Apple было бы слишком избыточным.

— Все эти факты о том, как был выбран символ для клавиши Command! Пруфы — раз (ссылка на объяснение от самой Сьюзен), два.

@iOS Dev — интересно об обыденном. 👍 — если инфа вас удивила.
Please open Telegram to view this post
VIEW IN TELEGRAM
Memory Warnings при разработке: определение и способы воспроизведения

⚠️ Если системе не хватает свободной памяти и она не может восстановить её, завершив приостановленные приложения, UIKit отправляет предупреждение о нехватке памяти работающим приложениям.

UIKit выдает предупреждения о нехватке памяти следующими способами:

🔘 Вызывая applicationDidReceiveMemoryWarning(_:) в app delegate.

🔘 Вызывая didReceiveMemoryWarning() в каждом из активных UIViewController.

🔘 C помощью didReceiveMemoryWarningNotification во все зарегистрированные observers.

🔘 Каждая из dispatch queues получает warning типа DISPATCH_SOURCE_TYPE_MEMORYPRESSURE.

Когда ваше приложение получает предупреждение о нехватке памяти, освободите как можно больше памяти так быстро, насколько это вообще возможно, с помощью следующих рекомендаций Apple:

1️⃣ Удалите ссылки на изображения, мультимедийные файлы или любые большие файлы данных, которые уже представлены на диске и могут быть повторно загружены позже.

2️⃣ Удалите ссылки на любые временные объекты, которые вам больше не нужны.

3️⃣ Если активные задачи могут потреблять значительный объем памяти, приостановите dispatch queues или ограничьте количество одновременных операций, выполняемых вашим приложением.

Если приложение не отдает достаточно памяти или же приложение использует слишком много памяти слишком быстро, iOS удалит приложение без предупреждения.

Иногда во время тестирования из-за этого приложение закрывается, но в отладчике ничего не появляется.

Что делать в таком случае?

🟢 На симуляторе: откройте Debug -> Simulate Memory Warning (или воспользуйтесь шорткатом CMD+SHIFT+M).

🟢 Приватное API — не используйте его в проде: UIControl().sendAction(Selector(("_performMemoryWarning")), to: UIApplication.shared, for: nil)

ℹ️ А чтобы зафорсить out of memory, есть ещё и такой способ.

@iOS Dev
Пример создания UICollectionViewCompositionalLayout

В iOS 13 Apple представила новый и очень мощный способ создания макетов для UICollectionView — UICollectionViewCompositionalLayout.

Он предоставляет декларативный способ создания богатых и сложных макетов для вашего приложения. Больше никаких сложных расчетов размеров, борьбы со вставками, размеров заголовков.

В композиционном макете используются три типа «строительных блоков»:

🔘 item — описывает свойства фактической ячейки, которые будут отображаться.

🔘 group — это самая мощная вещь в композиционном лэйауте! Больше не нужно вычислять, какой элемент должен быть больше, меньше, полной ширины или половинной ширины. Всю эту информацию достаточно описать в группе.

🔘 section — как следует из названия, описывает секцию. Секция имеет внутри одну группу и может иметь дополнительные элементы, такие как нижние и верхние хэдеры.

📖 В этой статье более детально разбираются определения и приводятся примеры создания.

@iOS Dev
This media is not supported in your browser
VIEW IN TELEGRAM
Архитектура MVVM за 90 секунд

📖 В этой статье вы найдете все необходимое, чтобы разобраться в этой популярной архитектуре iOS-приложений.

Шесть шагов, описанных в материале, затрагивают этапы от создания ViewModel до момента, когда ViewController сможет полагаться на ViewModel для извлечения и форматирования данных.

🛠 Поэкспериментировать самим можно с помощью кода.

📺 В формате короткого 🏴󠁧󠁢󠁥󠁮󠁧󠁿 видео материал доступен здесь.

@iOS Dev
Что такое Measurement type: определение, примеры и способы его использования

Measurement type — невероятно полезный инструмент в наборе инструментов разработчика Apple.

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

📖 В этом материале автор размышляет о причинах для встраивания в свои проекты, в особенности, для разных стран. При этом в статье приводятся способы использования, а также объясняется, как с помощью Measurement преобразовывать разные данные и применять локализацию.

ℹ️ Хотя этот пост посвящен Swift, полезно знать, что в Objective-C можно использовать NSMeasurement, и почти все, упомянутое в этом посте, доступно вам.

К сожалению, Measurement<UnitType>.FormatStyle предназначен только для Swift, и если вы используете Objective-C, придется полагаться на NSMeasurementFormatter для локализации.

💪 Преобразование и математические вычисления с помощью Measurement могут быть полезными, но реальная сила проявляется, когда вы получаете так много возможностей локализации, не прилагая больших усилия.

@iOS Dev
Please open Telegram to view this post
VIEW IN TELEGRAM
This media is not supported in your browser
VIEW IN TELEGRAM
Senior-разработчик объясняет архитектуру проекта новичкам😎
Please open Telegram to view this post
VIEW IN TELEGRAM
Как работает Bool.random() в Swift на самом деле?

Наверняка, в своих проектах каждый хоть раз использовал нечто вроде:

let randomInt = Int.random(in: 1..<5)
let randomFloat = Float.random(in: 1..<10)
let randomBool = Bool.random()


🤔 Но задумывались ли вы, что происходит на самом деле внутри? Иногда я смотрю на реализацию крутых вещей в ядре Swift, как например в посте про сортировку, и ищу материалы, объясняющие то или иное решение.

Так вот, в случае Bool полная реализация API будет получать необработанное значение UInt64 от генератора (он же RNG), сдвигать его вправо 17 раз и возвращать true, если первый бит результирующего значения равен 0.

Самое интересное в количестве, а именно, почему же 17?

Причина, по которой значение сдвигается ровно 17 раз, заключается в том, что (некоторые) слабые ГСЧ (генераторы случайных чисел) имеют лучшие свойства случайности в средних битах по сравнению с младшими/старшими битами.

Команда разработчиков Swift решила защитить нас от API, которые решили использовать эти ГСЧ вместо стандартного SystemRandomNumberGenerator.

ℹ️ Кстати, до пулл-реквеста, в котором реализовано это улучшение, Bool.random() просто возвращал generator.next() % 2 == 0.

📖 Почитать подробнее можно в ядре свифта или в более понятном источнике. А ещё рекомендую пост про UUID.

@iOS Dev
Как реализовать обновления в реальном времени с помощью Live Activity + Бонус

ℹ️ Live Activities будут представлены в iOS 16.1 как способ отображения актуальной информации на экране блокировки iPhone и в Dynamic Island.

📖 В этой статье автор разбирается с API с помощью создания приложения доставки, где пользователь будет получать обновления своего заказа прямо на экран блокировки своего телефона.

👩‍💻 Бонусом идёт модифицированный скрипт для отправки нужных пушей, взятый из документации Apple.

👨‍💻 Кроме этого материала, советую ознакомиться с официальной документацией, если вы планируете внедрять эту функциональность в свои приложения.

@iOS Dev
Please open Telegram to view this post
VIEW IN TELEGRAM
Создание и планирование локальных уведомлений с помощью async/await

После того как вы получите разрешение на отправку уведомлений, вам будет доступно управление уведомлениями с помощью user notification center.

📖 В этом руководстве рассказывается, как создавать такие уведомления, начиная с работы над контентом и заканчивая планированием с помощью триггера, основанного на времени.

@iOS Dev