iOS Dev
7.87K subscribers
1.23K photos
154 videos
1 file
1.54K links
👨‍💻Автор: Виктор Грушевский (@Viktorianec)

⚒️ База: https://boosty.to/ios_dev | 🤖 @iOSIQBot | https://iosiq.ru

🍏Канал об iOS-разработке, алгоритмах и архитектурах

⭐️ Подготовка к собесам

⭐️ Код. Много кода.

#ios #mobile #swift
Download Telegram
Более короткий синтаксис для работы с опциональными строками

Опциональные строки очень часто встречаются в коде Swift, например, многие объекты из UIKit отображают текст как «String?»

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

Хотя оператор nil-coalescing (например, ??) является отличным способом достижения этой цели, определение переменной типа orEmpty может значительно помочь в том, чтобы сделать наш код чище.
🔥34👍8❤‍🔥3🤔3😱3👏1
Какой алгоритм использует Swift для sort()?

💡 Этот вопрос из тех, которые вряд ли вы себе могли бы задать в пятницу, но если вам интересно, то внутри реализации алгоритма используется следующее:

1️⃣ Если менее, чем 20 элементов, то применяется сортировка вставками (insertion sort). В комментариях в коде уточняется, что именно этот тип лучше подходит для небольших областей.

2️⃣ Интроспективная сортировка (Introsort), включающая в себя быструю сортировку до определённой глубины рекурсии 2*floor(log(N)).

3️⃣ И переключается на пирамидальную сортировку (она же heapsort или сортировка кучей), когда глубина рекурсии превысит заранее установленный уровень.

Больше деталей в коде swift.

@iOS Dev — теперь вы, возможно, знаете больше😅
❤‍🔥42👍13❤5👏3🤯2
Упрощение внедрения зависимостей с помощью паттерна «Фасад» в iOS

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

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

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

📖 Эта статья предлагает отличную комбинацию двух паттернов проектирования (Facade и Dependency Injection).

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

@iOS Dev
👍19🔥5
Chisel — набор команд LLDB для помощи в отладке iOS-приложений

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

Для LLDB есть возможность импортировать подключаемые модули, что может значительно расширить возможности отладки. Chisel, инструмент, который содержит множество плагинов lldb — например, команду border, которая добавляет яркую рамку к UIView, чтобы вы могли быстро найти его на экране, и все эти плагины работают благодаря умному использованию команд e/po.

Несколько примеров команд, кроме border:

🟢 pviews — рекурсивно просматривает и выводит описание для key window.

🟢 visualize — можно открыть UIImage, CGImageRef, UIView, CALayer, NSData (для картинки), UIColor, CIColor, или CGColorRef в Preview.app на вашем маке.

🟢 fv — ищет вьюху в иерархии, чьё имя класса соответствует заданной регулярке.

🟢 presponder — выводит всю responder chain, начиная с данного объекта.

🟢 и много чего ещё.

Кстати, ещё с помощью Chisel можно пилить собственные команды и использовать их для отладки.

🛠 Ссылка на #opensource проект: Github.

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

📖 Расширенные приемы lldb для Swift — внедрение и изменение кода на лету.

📖 Танец в отладчике - вальс с LLDB. Пусть материал вышел и давно, но всё ещё может быть нам полезен.

👍 Рекомендую прочесть и сохранить себе в избранное.

@iOS Dev
👍34🔥7❤‍🔥3❤1
Посетитель или же Visitor — это один из паттернов, описанных в учебнике «Банды четырех», под названием «Design Patterns: Elements of Reusable Object-Oriented Software».

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

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

📖 Данный материал предназначен для знакомства с этим приемом. Автор подчёркивает, что знает о недостатках кода и возможностях его улучшения.

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

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

@iOS Dev
👍19🔥3👏2❤1
Создание переиспользуемой системы для сложных URL-запросов с помощью Swift

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

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

Foundation имеет встроенный механизм для этого — URLComponents с его свойством queryItems, но может оказаться довольно хлопотно каждый раз настраивать это для каждого запроса.

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

@iOS Dev
👏14👍10❤‍🔥2🎉1🤩1
😁16👍10🔥3🤯3❤‍🔥2🙏2
iOS Dev
Photo
Каким будет результат выполнения со скриншота выше?
Anonymous Quiz
1%
3
54%
2
18%
1
1%
0
2%
nil
13%
Код не скомпилируется
10%
Будет ошибка Index out of bounds
🤔37🔥9👍8🤯4😱4❤‍🔥2😁1🤩1
iOS Dev
Каким будет результат выполнения со скриншота выше?
Вопрос со скриншота не такой простой на первый взгляд, как кажется

😉Но и для этого есть объяснение, всё дело в том, что:

После dropFirst() у нас будет не Array, а ArraySlice. Тип ArraySlice позволяет быстро и эффективно выполнять операции над разделами большего (исходного) массива.

Вместо копирования элементов среза в новое хранилище, экземпляр ArraySlice представляет собой вид на хранилище исходного массива.

А поскольку ArraySlice представляет тот же интерфейс, что и Array, вы можете выполнять над срезом те же операции, что и над исходным массивом.

Это означает, что элемент по индексу 0 в ArraySlice — это тот же элемент по индексу 0 из исходного массива.

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

Это происходит потому, что ArraySlice не содержит элемента с индексом 0 исходного массива, а только элементы с индексами 1 и 2.

Если мы хотим получить первый или последний индекс получившегося фрагмента безопасным способом, мы должны использовать startIndex и endIndex. Ну, ещё можно использовать Array для доступа к нужному элементу (кому как больше нравится).

📖
Кстати, есть отличная статья, в которой рассматривается больше деталей.

@iOS Dev
👍74🔥15🤯14👏2
Два способа сохранить картинку в галерею на устройстве

🟢 Первый способ — используем метод времён Objective-C.

UIImageWriteToSavedPhotosAlbum(image: UIImage, completionTarget: Any?, completionSelector: Selector?, contextInfo: UnsafeMutableRawPointer?)

🟢 Второй способ связан с использованием PHPhotoLibrary.

Добавьте ключ NSPhotoLibraryAddUsageDescription (нужен для записи в галерею, не для чтения или изменения) в Info.plist и воспользуйтесь creationRequestForAsset для вашего UIImage:

PHPhotoLibrary.shared().performChanges {
_ = PHAssetChangeRequest.creationRequestForAsset(from: image)

} completionHandler: { (success, error) in

}


Если у вас есть доступ к URL-адресу, то можно использовать creationRequestForAssetFromImage(atFileURL: imageUrl), где imageURL - адрес нашего изображения.

А если нужно сохранить видео, то используйте creationRequestForAssetFromVideo(atFileURL: videoUrl)

@iOS Dev
👍22🔥5❤‍🔥3👏2
👍 Apple анонсировали серию презентаций с вопросами и ответами на тему App Store

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

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

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

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

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

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

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

@iOS Dev
🔥9👍7❤‍🔥2👏1
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
👍28🔥8❤‍🔥4👏1
🎉 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
👍14🔥4🤩2❤1
Как улучшить отклик приложения: 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 — делюсь советами не только для плавного скролла😅
🔥20❤‍🔥7👍6😁1🤯1
Защита данных в приложениях для 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 — защищайте файлы пользователей.
👍17❤‍🔥8🔥3🤩1
Реализация API-клиента для работы с запросами в Swift с использованием Async/Await

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

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

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

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

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

@iOS Dev
👍26❤‍🔥3🔥3❤1👏1
Использование DateFormatter и оценка его производительности

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

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

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

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

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

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

@iOS Dev
❤‍🔥14👍10👏3❤2🔥1
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
🔥13👍6❤‍🔥2👏1🤩1
Corner Radius, Shadow, и Border в Swift: создание, использование и комбинирование

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

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

@iOS Dev
👍25🔥5👏1
Простой способ работать с асинхронным кодом в Swift Playground

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

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

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

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

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

PlaygroundPage.current.finishExecution()

@iOS Dev
❤‍🔥16👍5🤯2👏1🤩1