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

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

#ios #mobile #swift
加入频道
👍 Apple анонсировали серию презентаций с вопросами и ответами на тему App Store

Обещают рассказать, как максимально эффективно использовать функции App Store.

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

Прямые презентации с вопросами и ответами будут проходить в течение августа в разных часовых поясах и на разных языках.

Требование: наличие девелоперской учетки.

Узнать больше: тут.

Зарегистрироваться: здесь.

Будет точно полезно инди-разработчикам и маркетологам.

@iOS Dev
NSPredicate в Swift: определение, примеры и один интересный факт

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

Хотя предикаты принято создавать непосредственно из экземпляров NSComparisonPredicate, NSCompoundPredicate и NSExpression, часто предикаты создаются с помощью обычных (форматных) строк.

Рассмотрим некоторые способы задания предикатов.

Простые сравнения. Пример: jobTitle == "Team Lead" или channelName == "iOS Dev".

Поиск без учета регистра и диакритических знаков, например, name contains[cd] "Bruce".

💡Интересный факт: здесь c это case-insensitive (без учёта регистра), а d - diacritic insensitive (игнорим диакритический знак, то есть если в поиске будет два символа c и ç, они попадут в условие).

Логические операции, например firstName like "Ivan" или lastName like "Ivanov".
Нельзя не уточнить, что like сработает как == для этого условия.

Ограничения временного диапазона, например, date between {$YESTERDAY, $TOMORROW}.

Относительные условия, например, group.name like "work*".

Агрегатные операции, например @sum.items.price < 1000.

БОНУС

🟢 Ключевое слово MATCHES можно использовать для поиска с помощью регулярки.
Пример: NSPredicate(format: "name MATCHES %@", query).

🟢 А для поиска строк, начинающихся или заканчивающихся заданным условием, пригодятся BEGINSWITH и ENDSWITH.

📖 Полный справочник по синтаксису можно посмотреть в документации.

📖 Вы также можете создавать предикаты, включающие переменные, используя метод evaluate(with:substitutionVariables:), чтобы предварительно определить предикат перед заменой конкретных значений в рантайме.

@iOS Dev
🎉 Live Activities доступны в iOS 16 beta 4

Live Activities помогают людям следить за тем, что происходит в вашем приложении в режиме реального времени, прямо с экрана блокировки. Теперь вы можете начать работу с Live Activities и новым фреймворком ActivityKit, который достепен в beta 4 iOS 16.

Пример использования

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

‼️ Обратите внимание, что Live Activities и ActivityKit не будут включены в первый публичный релиз iOS 16.

Отправлять приложения, включающие Live Activities, можно будет позже.

@iOS Dev
Как улучшить отклик приложения: 10 советов от инженеров Apple

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

Приложения с зависаниями (задержками отклика) или дёрганым поведением на экране разрушают эту иллюзию.

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

100 мс — это максимальная отсечка для задержек при непосредственном взаимодействии с пользователем. Более короткая задержка редко заметна.

5 мс — это порог для достижения плавного скролла на экране.

Для непрерывного скролла новый фрейм должен быть готов каждый раз при обновлении экрана. На устройствах Apple это может происходить 120 раз в секунду, или каждые 8,3 мс. В зависимости от системных условий и задач в приложении, у вас может не быть полных 8,3 мс для подготовки следующего обновления экрана.

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

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

2️⃣ Проанализируйте, какие части вашего приложения должны выполняться в основном потоке, а какие нет.

3️⃣ Избегайте слишком большого количества потоков.
Dispatch и OperationQueue поддерживают внутренний пул рабочих потоков, настроенных на емкость и нагрузку устройства. Используйте эти технологии вместо создания собственных фоновых потоков для сохранения баланса.

4️⃣ Избегайте лагов, сводя к минимуму время обновления для view.
Чтобы обеспечить плавную анимацию, которая выглядит как непрерывное движение, устройства Apple обновляют экран до 120 раз в секунду. Когда ваше приложение находится в foreground (на переднем плане, кому как привычнее), код отрисовки в основном потоке должен быть завершен до того, как потребуется следующий фрейм, чтобы избежать пропуска кадров и появления рывков.

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

6️⃣ Напишите тесты производительности, чтобы обеспечить быстрое выполнение кода, привязанного к основному потоку.

7️⃣ Ищите зависания и потенциальные риски, которые могут к этому привести.

8️⃣ Попробуйте найти сами причины зависаний. Обратите внимание на Thread State Trace instrument.

9️⃣ В целом чаще используйте Instruments для обнаружения узких мест приложения.

🔟 Уделяйте внимание метрикам и отчётам непосредственно от приложения.

@iOS Dev — делюсь советами не только для плавного скролла😅
Защита данных в приложениях для iOS

Защита данных — это функция iOS для предотвращения несанкционированного доступа.

Она включается автоматически, после установки активного пароля устройства.

Процессы шифрования и дешифрования выполняются автоматически и аппаратно ускоряются.

Доступно четыре уровня защиты, каждый из которых определяет уровень доступа. При создании файла, iOS автоматически применит дефолтный, если не указано иное.

No protection.
Файл всегда доступен.

Complete until first user authentication.
Это уровень по умолчанию. Файл недоступен до первой разблокировки устройства. После неё файл остается доступным до выключения или перезагрузки устройства.

Complete unless open.
Открыть существующие файлы можно только после разблокировки устройства. Если файл уже открыт, вы можете продолжать получать доступ к нему даже после того, как пользователь заблокирует устройство. Вы также можете создавать новые файлы и получать к ним доступ, пока устройство заблокировано или разблокировано.

Complete.
Доступ к файлу возможен только после разблокировки устройства.

Методы для создания и изменения уровня защиты

1️⃣ Чтобы создать и зашифровать новый файл за один шаг, создайте объект данных с содержимым файла и вызовите метод write(to:options:).

2️⃣ Чтобы изменить уровень защиты данных существующего файла, используйте метод setResourceValue(_:forKey:) для NSURL.

Управление доступом к зашифрованным файлам

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

🔘Выберите уровень защиты данных, соответствующий вашим потребностям.

🔘Используйте методы applicationProtectedDataWillBecomeUnavailable(_:) и applicationProtectedDataDidBecomeAvailable(_:) для закрытия и повторного открытия файлов с уровнем защиты completeFileProtection.

@iOS Dev — защищайте файлы пользователей.
Реализация API-клиента для работы с запросами в Swift с использованием Async/Await

Каждый бэкенд имеет свои причуды и обычно требует оптимизированного под него клиента.

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

C недавними изменениями Swift автор расскажет, как наиболее эффективно использовать нативные технологии Apple: URLSession, Codable, Async/Await и Actors.

👏 Автор этой статьи — Alex Grebenyuk, инженер-программист с многолетним опытом работы в отрасли.

🛠 Среди его проектов, например, Nuke, Pulse и многие другие, о которых вы, скорее всего, слышали или даже применяли при работе над своими проектами.

@iOS Dev
Использование DateFormatter и оценка его производительности

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

💡Создание DateFormatterдорогостоящая операция.

Но насколько именно он медленный, и какие части наиболее неэффективны?

На эти вопросы попробуют помочь ответить две статьи:

📖 Цена использования DateFormatter — примеры и измерения.

📖 Как использовать DateFormatter в Swift.

@iOS Dev
This media is not supported in your browser
VIEW IN TELEGRAM
Добавляем код Swift в качестве собственной команды LLDB

😎 Знаете ли вы, что возможно определить свою собственную команду LLDB, используя исключительно код Swift?

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

1️⃣ Добавление вашей первой команды LLDB.
2️⃣ Добавление команды LLDB с аргументами.
3️⃣ Преобразование сложного кода Swift в команду LLDB.

Простейшую команду и принцип её добавления можно увидеть на гифке выше.

А ещё статью можно рассматривать как дополнение к этому посту.

@iOS Dev
Corner Radius, Shadow, и Border в Swift: создание, использование и комбинирование

📖 В этой статье на простых примерах объясняется, как скруглить углы, применить тень и границы ко всем видам вьюх, включая UIViews, UIButtons и UIImageViews.

Также рассказывается про решение для одновременного использования shadow и corner radius, что для новичков может оказаться непростой задачей.

@iOS Dev
Простой способ работать с асинхронным кодом в Swift Playground

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

Итак, чтобы ваш код сработал, есть решение в одну строку:

💡 Для этого нужно установить значение needIndefiniteExecution в true.

😎 Не забудьте импортировать PlaygroundSupport.

Кстати, чтобы остановить выполнение, можно воспользоваться следующим методом:

PlaygroundPage.current.finishExecution()

@iOS Dev
Как добавить кастомный шрифт в приложение для iOS?

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

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

2️⃣ Откройте ваш Info.plist. Если в вашем проекте его нет, то вкладку Info.

3️⃣ Добавьте ключ Fonts provided by application. Нужный шрифт из первого шага необходимо добавить вместе с его расширением.

4️⃣ Пожалуй, самый важный пункт. Название семейства шрифтов может не совпадать с названием файла, скорее всего, так и будет чаще всего. Поэтому нам необходимо получить имя нашего шрифта с помощью следующего метода:

for family in UIFont.familyNames.sorted() {
let names = UIFont.fontNames(forFamilyName: family)
print("Family: \(family) Font names: \(names)")
}


Бонус: вы также можете найти нужное имя, используя приложение «Шрифты» (можно и вбить Font в Launchpad).

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

label.font = UIFont(name: "CUSTOM_FONT_NAME", size: 25)

Интересный факт

📖 Lorem ipsum, который выступает заглушкой во всех (ну ладно, почти во всех) текстах на самом деле не что иное как искажённый отрывок из философского трактата Марка Туллия Цицерона «О пределах добра и зла», написанного в 45 году до н. э. на латинском языке.

@iOS Dev — In iOS Dev verĭtas
Как улучшить читаемость крупных чисел в Swift?

💡 Для этого может пригодиться нижнее подчёркивание или же просто _.

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

Кстати, в Swift нет ограничений на позицию нижнего подчёркивания, так что вы можете использовать и третий вариант. Но, пожалуйста, не делайте так😅

@iOS Dev
This media is not supported in your browser
VIEW IN TELEGRAM
Интерактивные переходы для UIViewController в Swift: терминология и пример реализации

iOS предоставляет нам несколько красивых переходов для UIViewController, таких, например, как push и pop, но почему бы не сделать и свой собственный.

Кастомные анимации для переходов у UIViewController могут значительно улучшить восприятие пользователей и выделить ваше приложение из общей массы.

В процессе вы добавите несколько пользовательских анимаций переходов UIViewController в небольшое приложение для игры в угадайку. К концу статьи вы узнаете:

🟢 Как устроен API переходов.

🟢 Как представлять и удалять UIViewControllers с помощью пользовательских переходов.

🟢 Как создавать интерактивные переходы.

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

Кстати, эту статью можно рассматривать вместе с этим постом.

@iOS Dev
Как диагностировать узкие места при сборке ваших проектов на Swift?

Тайпчекер в Swift (инструмент проверки типов) постоянно улучшается, пусть раньше и был узким местом для производительности при компиляции.

В 2016 году Джордан Роуз добавил флаг компилятора Swift, который выдавал предупреждения в Xcode для функций, которые слишком долго компилировались или, если выразиться точнее, слишком долго проверялись.

А с Xcode 9 появился новый, аналогичный флаг для проверки выражений.

Речь ниже пойдёт о следующих двух флагах

-warn-long-function-bodies

Bryan Irace и Soroush Khanlou изначально описали флаг -warn-long-function-bodies. Вы можете указать порог в миллисекундах, при достижении которого будет выдаваться предупреждение.

Например: -Xfrontend -warn-long-function-bodies=100 будет выдавать предупреждение в Xcode для любой функции, проверка типа которой занимает более 100 мс.

Этот флаг всегда считался экспериментальным, как отметил Джордан в своем оригинальном коммите, но он всё ещё актуален.

-warn-long-expression-type-checking

С Xcode 9 появился новый аналогичный флаг для тайпчекинга выражений, а не только для функций. Однако на этот раз флаг появился в официальных примечаниях к выпуску Xcode 9 GM.

Компилятор может предупреждать нас с помощью этого флага об отдельных выражениях, проверка типов которых занимает много времени.

💡 Советы по использованию

Имейте в виду, что если порог слишком низкий, например 10 мс, то вы получите массу предупреждений, которые невозможно исправить.

Стоит немного поэкспериментировать со значениями, чтобы найти по-настоящему узкие места. Автор этой статьи предлагает начать с 200, а если ваш проект крупный - с 500, и пытаться уменьшить его с течением времени.

Иначе вы потратите много времени, пытаясь заставить все функции и выражения компилироваться менее чем за 200 мс.

Кроме того, рекомендуется использовать эти флаги только для конфигураций сборки DEBUG.

@iOS Dev
Что использовать вместо //TODO в коде?

Периодически бывает необходимо добавить напоминание или даже вывод ошибки.

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

В таком случае кроме традиционных комментариев на помощь могут прийти #warning и #error.

#warning заставит Xcode выдать предупреждение при сборке проекта, а #error покажет ошибку компиляции, поэтому код не соберётся вообще 😅 (будьте аккуратны!).

Кстати, и #warning, и #error будут корректно работать вместе с директивой #if (конечно, если условие будет истинно). Например, как в коде ниже:

#if os(macOS)
#error("Эта библиотека пока что не поддерживается на маке. Используйте другое решение")
#endif


А пример для #error со скриншота будет актуален если вы раздаёте ключи для вашей библиотеки, без которых она не будет работать.

Например, Firebase вполне мог бы использовать нечто подобное.

@iOS Dev — дополняем ваш инструментарий простыми средствами.
This media is not supported in your browser
VIEW IN TELEGRAM
Эксперимент с Live Activities — велокомпьютер на локскрине

Прошло менее недели с анонса доступности Live Activities для разработчиков в четвёртой бетке iOS 16, а Ole Begemann уже успел попробовать добавить функциональность в своё приложение.

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

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

Уже сейчас автор поднимает ряд важных вопросов:

1️⃣ Для Live Activities не нужно явного одобрения пользователя.

2️⃣ Приложение должно быть на переднем плане.
С другой стороны, это ограничение может не быть проблемой для большинства случаев использования и, вероятно, значительно сократит спам/злоупотребления.

3️⃣ Приложение должно продолжать работать в фоновом режиме, чтобы обновлять активность (или использовать push-уведомления).

4️⃣ Сложности с эстетикой внешнего вида.
Автор пытался найти в API метод для задания цветового стиля, но пока что безуспешно и решил захаркдодить foreground color. Может быть, Apple в будущем расширят возможности.

5️⃣ Анимацию нельзя отключить.
Возможно, полный контроль над анимацией также упрощает для Apple интеграцию Live Activity в постоянно включенный дисплей, который, вероятно появится в следующем айфоне.

6️⃣ Общий код для приложения и виджета.
Live Activity очень похожа на виджет: UI должен находиться в расширении виджета вашего приложения.

7️⃣ Проблема с доступностью виджета на разных осях.
Если у вас есть существующие виджеты и вам пока не требуется iOS 16, обходной путь — добавить вторую цель расширения виджета только для Live Activity.

📖 Более подробно о выводах автора статьи можно прочесть здесь.

@iOS Dev
Алгоритм Дейкстры в Swift, используя GameplayKit. Погодите, что?!

Если вы когда-либо слышали что-то про теорию графов, то наверняка знакомы с алгоритмом Дейкстры.
Краткий термин для понимания, для чего он: алгоритм находит кратчайшие пути от одной из вершин графа до всех остальных, важное условие — он работает для рёбер без отрицательного веса.

Примеры задач, которые можно решить с помощью данного алгоритма:

Дана сеть автомобильных дорог, соединяющих города. Некоторые дороги односторонние. Требуется найти кратчайшие пути от исходного города до любого другого (если двигаться можно только по дорогам).

Имеется некоторое количество авиарейсов между городами мира, для каждого известна стоимость. Требуется найти самый дешёвый билет.

📖 Федерико Занетелло в одной из своих статей обратил внимание на то, что иногда для решения сложных задач можно пойти по нестандартному пути (кратчайшему, я бы сказал😅).

Что умеет GameplayKit?

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

Пожалуй, вы уже видите, куда клонит автор?

🛠 С помощью подкласса для GKGraphNode и нескольких строк кода автор покажет, как можно реализовать нахождение кратчайшего пути и использовать в вашем коде.

🛠 Сам проект также опенсорсный и находится здесь.

P.S. Заголовок материала показывает не всю суть, так как GameplayKit внутри может использовать и алгоритм Форда-Беллмана. Спасибо автору, который об этом также указывает.

И ещё один полезный вывод от Федерико заключается в том, что использовать коробочное решение иногда лучше, так как, например, GameplayKit поддерживается инженерами Apple постоянно, а наши с вами ресурсы не бесконечны.

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

@iOS Dev
Традиционное исследование зарплат от Хабр Карьеры

😎 И кто тут у нас лидер?

Краткие выводы исследования

🟢 Архитекторы ПО в среднем зарабатывают больше остальных, 285 000 ₽. А вот мобайл на втором месте, средняя зарплата 171 000 ₽.

🟢 По языкам программирования пальму первенства перехватил Objective-C со средней зп в 250 000 ₽. По Swift динамика не изменилась, согласно исследованию коллеги получают 200 000 ₽.
На Kotlin и Java такого разброса, к слову нет, там 185к и 180к, соответственно.

Самые щедрые на зп среди компаний РФ — SkyEng, Avito, Mail ru group.

Больше всего выросли зарплаты у архитекторов ПО (+13%), а упали в геймдеве (-8%).

Зарплата выросла в большинстве городов. Ощутимый рост был в Красноярске (+33%), Волгограде (+25%) и Перми (+20%). В Питере и Омске зарплаты не изменились😔.

@iOS Dev — о важном
Сортировка данных с помощью KeyPathComparator в iOS 15

😉 Скорее всего, для сортировок вы чаще используете sorted(by:), так как KeyPathComparator был добавлен в Foundation в iOS 15 и macOS 12 (а у кого-то на проекте поддерживается явно больше двух последних версий iOS, и юзать available накладно).

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

Нам достаточно указать только keyPath, по которому наши значения будут сравниваться с помощью SortComparator.

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

В результате получится следующее:

Senior 350000
Senior 300000
Middle 250000
Middle 220000
Junior 200000
Junior 120000
Junior 100000


🧐 В целом, использование очень похоже на NSSortDescriptor, который использовался для сортировки NSArray и NSMutableArray.

@iOS Dev
Как получить все слова из заданной строки?

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

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

@iOS Dev
Подборка материалов для подготовки к собеседованиям

Ключевые темы этого поста: память, ссылки, side table и многое другое.

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

🗒 Для удобства разбил на два блока — русскоязычный и англоязычный, пост планирую расширять и обновлять.


🇷🇺 Материалы на русском языке

🔗 Как устроен счётчик ссылок в Swift?

🔗 Память в Swift от 0 до 1

🔗 Swift 4 - слабые ссылки

🔗 Память в Swift: стек, куча, ARC


🏴󠁧󠁢󠁥󠁮󠁧󠁿 Материалы на английском языке

🔗 Advanced iOS Memory Management with Swift: ARC, Strong, Weak and Unowned Explained

🔗 Value Types and Reference Types in Swift

🔗 ARC and Memory Management in Swift

🔗 Discover Side Tables - Weak Reference Management Concept in Swift

🔗 A deep dive into Swift reference counting

🔗 Weak self, a story about memory management and closure in Swift (резюме по статье - здесь)

🔗 Memory Management in Swift: Understanding Strong, Weak and Unowned References

🔗 О ловушках в замыканиях

🔗 Memory layout in Swift (материал разбит на два блока, резюме — здесь)

🔗 Вам не (всегда) нужно использовать [weak self]

🔗 Погружение в управление памятью в Swift


Способы для поиска утечек памяти и отладки таких моментов

🔗 Простой способ обнаружить retain cycle в UIViewController

🔗 Everything you need to know about Memory Leaks in iOS

🔗 3 Different Techniques to Find Memory Leaks in iOS

Конечно, многие из статей затрагивают общие моменты, но посмотреть на что-то под иным углом не помешает.

Лучшее спасибо — 👍❤️🔥👏🎉❤️‍🔥.

😃 iOS Dev🐱 Доступ к необычным эффектам
Please open Telegram to view this post
VIEW IN TELEGRAM