Взаимозаменяемое использование типов CGFloat и Double
SE-0307 в Swift 5.5 добавляет небольшое, но тем не менее очень полезное нововведение: компилятор будет автоматически уметь конвертировать между CGFloat и Double там где это нужно. Это значит, что мы сможем выполнять такие операции как умножение и деление без приведение типов.
Swift будет всегда отдавать предпочтение Double, чтобы предотвратить потерю точности. Более того, все описанное выше реализовано путем неявного использование нужного инициализатора для конвертации. Это значит, что это нововведение не меняет никакое с существующих API.
Source
#tips #core #basic
SE-0307 в Swift 5.5 добавляет небольшое, но тем не менее очень полезное нововведение: компилятор будет автоматически уметь конвертировать между CGFloat и Double там где это нужно. Это значит, что мы сможем выполнять такие операции как умножение и деление без приведение типов.
Swift будет всегда отдавать предпочтение Double, чтобы предотвратить потерю точности. Более того, все описанное выше реализовано путем неявного использование нужного инициализатора для конвертации. Это значит, что это нововведение не меняет никакое с существующих API.
Source
#tips #core #basic
Привет, СВИФТЕРЫ👋🏻
Врываемся в ваше воскресенье с крутой новостью! Теперь на нашем канале доступны комментарии к постам.
Задавайте любые вопросы, пишите пожелания к контенту, общайтесь между собой и учите Swift вместе😉
Ну что, пообщаемся?
Врываемся в ваше воскресенье с крутой новостью! Теперь на нашем канале доступны комментарии к постам.
Задавайте любые вопросы, пишите пожелания к контенту, общайтесь между собой и учите Swift вместе😉
Ну что, пообщаемся?
Как добавить Pull-to-Refresh в UITableView или UICollectionView?
Swift предоставляет нам готовый функционал для этой цели, который реализован с помощью класса UIRefreshControl. Любой наследник UIScrollView имеет свойство refreshControl, а поскольку UITableView и UICollectionView как раз являются наследниками, нам достаточно присвоить экземпляр UIRefreshControl этому свойству.
Если вы хотите получить что-то более уникальное, например добавить свою анимацию, тогда можно обратить внимание на библиотеки как CRRefresh. Правда, по моему опыту, все они работают плохо и имеют те или иные проблемы.
Source
#languageGuide #UIRefreshControl #basic
Swift предоставляет нам готовый функционал для этой цели, который реализован с помощью класса UIRefreshControl. Любой наследник UIScrollView имеет свойство refreshControl, а поскольку UITableView и UICollectionView как раз являются наследниками, нам достаточно присвоить экземпляр UIRefreshControl этому свойству.
Если вы хотите получить что-то более уникальное, например добавить свою анимацию, тогда можно обратить внимание на библиотеки как CRRefresh. Правда, по моему опыту, все они работают плохо и имеют те или иные проблемы.
Source
#languageGuide #UIRefreshControl #basic
Используем String в качестве SectionIdentifierType для UITableViewDiffableDataSource
UITableViewDiffableDataSource предоставляет абсолютно новое API для работы с данными таблицы. Если вы уже имеете опыт использования, то знаете, что нам нужно предоставить два дженерика: SectionIdentifierType, ItemIdentifierType.
В качестве ItemIdentifierType обычно выступает модель, которую мы планируем отображать в таблице. SectionIdentifierType же, как следует из названия, описывает секции нашей таблицы. Классическим подходом будет использование отдельного enum для этих задач, если секций несколько. Тем не менее, если мы имеем дело только с одной, то таким образом создадим ненужный шаблонный (boilerplate) код.
Поскольку строки в Swift Hashable по умолчанию, можно использовать String в качестве SectionIdentifierType.
Source
#tips #tableView #intermediate
UITableViewDiffableDataSource предоставляет абсолютно новое API для работы с данными таблицы. Если вы уже имеете опыт использования, то знаете, что нам нужно предоставить два дженерика: SectionIdentifierType, ItemIdentifierType.
В качестве ItemIdentifierType обычно выступает модель, которую мы планируем отображать в таблице. SectionIdentifierType же, как следует из названия, описывает секции нашей таблицы. Классическим подходом будет использование отдельного enum для этих задач, если секций несколько. Тем не менее, если мы имеем дело только с одной, то таким образом создадим ненужный шаблонный (boilerplate) код.
Поскольку строки в Swift Hashable по умолчанию, можно использовать String в качестве SectionIdentifierType.
Source
#tips #tableView #intermediate
Как удалить десятичную дробь из числа с плавающей запятой, если она равна 0?
Это простое расширение убирает десятичную дробь из числа с плавающей запятой, если она равна 0. Это пригодится в тех случаях, когда нам нужно сделать красивый вывод числа где-то в пользовательском интерфейсе. Мы используем truncatingRemainder (тот же %), чтобы найти остаток от деления. Если оно равно нулю, то убираем плавающую точку, форматируя строку в виде "%.0f", в противном же случае просто конвертируем Double в String без каких-либо изменений.
Source
#handyExtensions #double #basic
Это простое расширение убирает десятичную дробь из числа с плавающей запятой, если она равна 0. Это пригодится в тех случаях, когда нам нужно сделать красивый вывод числа где-то в пользовательском интерфейсе. Мы используем truncatingRemainder (тот же %), чтобы найти остаток от деления. Если оно равно нулю, то убираем плавающую точку, форматируя строку в виде "%.0f", в противном же случае просто конвертируем Double в String без каких-либо изменений.
Source
#handyExtensions #double #basic
Привет, свифтеры🙂
Сегодня мы вводим на канал новую рубрику #MockInterview, которая даст вам возможность потренироваться отвечать на технические вопросы и даже подготовит к предстоящим собеседованиям.
В этой рубрике мы будем задавать вам вопросы, которые касаются программирования на Swift, чтобы вы в процессе ответа вспомнили давно известную вам информацию, а также могли узнать много нового.
Естественно, мы тоже будем отвечать на заданные вопросы и объясним, почему ответы именно такие. Но постарайтесь не подглядывать в ответ сразу, сначала поразмыслите над вопросом сами😉
Сегодня мы вводим на канал новую рубрику #MockInterview, которая даст вам возможность потренироваться отвечать на технические вопросы и даже подготовит к предстоящим собеседованиям.
В этой рубрике мы будем задавать вам вопросы, которые касаются программирования на Swift, чтобы вы в процессе ответа вспомнили давно известную вам информацию, а также могли узнать много нового.
Естественно, мы тоже будем отвечать на заданные вопросы и объясним, почему ответы именно такие. Но постарайтесь не подглядывать в ответ сразу, сначала поразмыслите над вопросом сами😉
#MockInterview
Вопрос: Можно ли получить доступ к private свойству внутри extension? 💬
Ответ: Да, мы можем получить доступ к private свойству внутри extension, но только при условии, что это extension находится внутри одного и того же файла, что и class, struct или enum. Если мы попытаемся расширить тип данных за пределами файла, private свойства доступны не будут.
Объяснение: Расширения, которые находятся в том же файле, что и class, struct или enum, которые они расширяют, ведут себя так, как если бы код в extension был написан как часть самого исходного типа.
В результате мы можем:
- Объявить private свойство в самом типе и достучаться к этому свойству из расширений в том же файле.
- Объявить private свойство в одном расширении и получите доступ к этому свойству из другого расширения в том же файле.
- Объявить private свойство в расширении и получите доступ к этому свойству из самого типа в том же файле.
#accessControl #basic
Вопрос: Можно ли получить доступ к private свойству внутри extension? 💬
Ответ: Да, мы можем получить доступ к private свойству внутри extension, но только при условии, что это extension находится внутри одного и того же файла, что и class, struct или enum. Если мы попытаемся расширить тип данных за пределами файла, private свойства доступны не будут.
Объяснение: Расширения, которые находятся в том же файле, что и class, struct или enum, которые они расширяют, ведут себя так, как если бы код в extension был написан как часть самого исходного типа.
В результате мы можем:
- Объявить private свойство в самом типе и достучаться к этому свойству из расширений в том же файле.
- Объявить private свойство в одном расширении и получите доступ к этому свойству из другого расширения в том же файле.
- Объявить private свойство в расширении и получите доступ к этому свойству из самого типа в том же файле.
#accessControl #basic
lazy теперь работает в локальном контексте (local context)
Используя ключевое слово lazy, мы можем реализовать свойство, начальное значение которого не вычисляется до первого использования. Начиная со Swift 5.5, можно использовать lazy внутри функций. На практике это позволит проводить оптимизацию, когда мы имеем какое-то условия if-else и не хотим проводить затратные вычисления на то, что нам не нужно.
Source
#languageGuide #lazy #intermediate
Используя ключевое слово lazy, мы можем реализовать свойство, начальное значение которого не вычисляется до первого использования. Начиная со Swift 5.5, можно использовать lazy внутри функций. На практике это позволит проводить оптимизацию, когда мы имеем какое-то условия if-else и не хотим проводить затратные вычисления на то, что нам не нужно.
Source
#languageGuide #lazy #intermediate
Как определить, включен ли у пользователя режим энергосбережения?
Когда пользователь включает режим энергосбережения, ваш код должен избегать слишком энергозатратных действий. Например, вы хотите выполнить какую-то миграцию или синхронизацию с облаком, но откладываете её на определенное время, чтобы не нагружать батарею.
Существует два подхода к проверке подключения режима энергосбережения: получить информацию из переменной isLowPowerModeEnabled напрямую или подписаться на изменения подключения, используя NotificationCenter.
Source
#tips #lowPowerMode #basic
Когда пользователь включает режим энергосбережения, ваш код должен избегать слишком энергозатратных действий. Например, вы хотите выполнить какую-то миграцию или синхронизацию с облаком, но откладываете её на определенное время, чтобы не нагружать батарею.
Существует два подхода к проверке подключения режима энергосбережения: получить информацию из переменной isLowPowerModeEnabled напрямую или подписаться на изменения подключения, используя NotificationCenter.
Source
#tips #lowPowerMode #basic
Typealiases с дженериками
Мало кто использует эту особенность Swift в своих проектах. Однако она может здорово улучшить некоторые участки кода и убрать ненужный шаблонный (boilerplate) код.
Typealiases могут использоваться в комбинации с generic типами.
Что самое интересное, мы можем явно указать конкретные типы для некоторых (или всех) generic параметров существующего типа. В обратную сторону, кстати, это не работает: новые параметры в typealiase вводить нельзя.
Source
#tips #generics #intermediate
Мало кто использует эту особенность Swift в своих проектах. Однако она может здорово улучшить некоторые участки кода и убрать ненужный шаблонный (boilerplate) код.
Typealiases могут использоваться в комбинации с generic типами.
Что самое интересное, мы можем явно указать конкретные типы для некоторых (или всех) generic параметров существующего типа. В обратную сторону, кстати, это не работает: новые параметры в typealiase вводить нельзя.
Source
#tips #generics #intermediate
Используем App Group для доступа к Realm из других приложений или расширений
App Group позволяет нескольким приложениям от одного разработчика получить доступ к общему контейнеру, в котором можно хранить и использовать какие-то данные. Поскольку Realm держит базу в файле, мы можем поместить этот файл в общий контейнер и получить доступ к нему из других наших приложений или расширений.
Для этого нужно в конфигурации Realm указать в качестве fileURL ссылку на этот общий контейнер. Получить ее можно, используя:
containerURL(forSecurityApplicationGroupIdentifier:)
Source
#tips #appGroup #advanced
App Group позволяет нескольким приложениям от одного разработчика получить доступ к общему контейнеру, в котором можно хранить и использовать какие-то данные. Поскольку Realm держит базу в файле, мы можем поместить этот файл в общий контейнер и получить доступ к нему из других наших приложений или расширений.
Для этого нужно в конфигурации Realm указать в качестве fileURL ссылку на этот общий контейнер. Получить ее можно, используя:
containerURL(forSecurityApplicationGroupIdentifier:)
Source
#tips #appGroup #advanced
Различия между let и var
Когда в Swift нужно связать имя (например, "username" или "balance") со значением определенного типа (например, строка "Den" или число 96.23), используются константы и переменные.
Чтобы объявить константу, используем ключевое слово let, для переменной – var. Изменить значение константы после того, как мы ее объявили, нельзя, переменную же мы можем менять сколько угодно раз.
На скриншоте видим:
maxPasswordLenght – константа со значением 64, поскольку максимальная длина пароля в приложении фиксированная, и менять ее мы не будем;
currentPasswordLenght – переменная, потому что ее значение напрямую зависит от значения, которое пользователь вводит в текстовом поле.
Source
#languageGuide #properties #basic
Когда в Swift нужно связать имя (например, "username" или "balance") со значением определенного типа (например, строка "Den" или число 96.23), используются константы и переменные.
Чтобы объявить константу, используем ключевое слово let, для переменной – var. Изменить значение константы после того, как мы ее объявили, нельзя, переменную же мы можем менять сколько угодно раз.
На скриншоте видим:
maxPasswordLenght – константа со значением 64, поскольку максимальная длина пароля в приложении фиксированная, и менять ее мы не будем;
currentPasswordLenght – переменная, потому что ее значение напрямую зависит от значения, которое пользователь вводит в текстовом поле.
Source
#languageGuide #properties #basic
Друзья, новость для вас❗️
Swifter расширяет свои границы, и теперь у нас есть аккаунт на Medium. Если среди вас есть активные пользователи данной платформы, будем рады взаимодействовать с вами и там🤗
Ссылка на SWIFTER | Блог про Swift в Medium:
https://medium.com/@BlogSwift
А с подписчиками нашего канала, которые верны Telegram, пообщаемся совсем скоро в новом обучающем посте. Ждите)
Swifter расширяет свои границы, и теперь у нас есть аккаунт на Medium. Если среди вас есть активные пользователи данной платформы, будем рады взаимодействовать с вами и там🤗
Ссылка на SWIFTER | Блог про Swift в Medium:
https://medium.com/@BlogSwift
А с подписчиками нашего канала, которые верны Telegram, пообщаемся совсем скоро в новом обучающем посте. Ждите)
Как создать UIImage со сплошной заливкой и заданным размером?
В сегодняшнем посте из серии #handyExtensions я покажу, как, используя UIGraphicsRendererContext, можно создать изображения со сплошной заливкой определенного размера.
Логика очень простая:
1. Создаем контекст с помощью UIGraphicsBeginImageContextWithOptions. Это своего рода полотно, где мы можем рисовать.
2. Устанавливаем цвет для заливки.
3. Делаем заливку нужного нам размера.
4. Рендерим в изображения.
После того, как мы зарендерим изображения, нужно очистить контекст, используя UIGraphicsEndImageContext.
Source
#handyExtensions #images #basic
В сегодняшнем посте из серии #handyExtensions я покажу, как, используя UIGraphicsRendererContext, можно создать изображения со сплошной заливкой определенного размера.
Логика очень простая:
1. Создаем контекст с помощью UIGraphicsBeginImageContextWithOptions. Это своего рода полотно, где мы можем рисовать.
2. Устанавливаем цвет для заливки.
3. Делаем заливку нужного нам размера.
4. Рендерим в изображения.
После того, как мы зарендерим изображения, нужно очистить контекст, используя UIGraphicsEndImageContext.
Source
#handyExtensions #images #basic
Улучшаем состояние AppDelegate с помощью сервисов
По мере того, как растет приложение, растет и логика в AppDelegate. Инициализация SDK, обработка диплинков, пуш-уведомления и многое другое. Читаемость этого файла сильно падает, он превращается в огромную кучу кода, который сложно поддерживать.
Разработчики по-разному избегают этой ситуации: с помощью команд, компоновщика, медиатора. Сегодня я поделюсь с вами библиотекой, которую использую в своих проектах.
PluggableApplicationDelegate решает описанную проблему с помощью сервисов, причем для каждой задачи можно создавать отдельный. Например, для настройки FacebookSDK вы создадите сервис, в котором сможете произвести инициализацию, обработать отложенные глубинные ссылки и т.д.
Source / PluggableApplicationDelegate
#shareLibrary #appDelegate #basic
По мере того, как растет приложение, растет и логика в AppDelegate. Инициализация SDK, обработка диплинков, пуш-уведомления и многое другое. Читаемость этого файла сильно падает, он превращается в огромную кучу кода, который сложно поддерживать.
Разработчики по-разному избегают этой ситуации: с помощью команд, компоновщика, медиатора. Сегодня я поделюсь с вами библиотекой, которую использую в своих проектах.
PluggableApplicationDelegate решает описанную проблему с помощью сервисов, причем для каждой задачи можно создавать отдельный. Например, для настройки FacebookSDK вы создадите сервис, в котором сможете произвести инициализацию, обработать отложенные глубинные ссылки и т.д.
Source / PluggableApplicationDelegate
#shareLibrary #appDelegate #basic
Как сделать аббревиатуру для числа?
Когда нужно отобразить огромное число в пользовательском интерфейсе (скажем, количество лайков или подписчиков), зачастую показывать число полностью не имеет смысла. Гораздо удобнее использовать агрегированное представление в виде "12M" или "1.5K".
Данное расширение позволяет получить в виде аббревиатуры числа вплоть до квадриллиона. Если кратко, то логика такая:
1. Есть список аббревиатур "KMBTQ". Проходимся по нему с конца, потому что представление должно быть как можно компактнее.
2. Для каждой аббревиатуры определяем фактор. Для тысяч это ЧИСЛО/10^3 (10 в степени 3).
3. Если фактор меньше нуля, число слишком маленькое для этой аббревиатуры, поэтому двигаемся дальше.
4. Если фактор больше нуля, значит к фактору добавляем нужную аббревиатуру и получаем результат.
Source
#handyExtensions #int #intermediate
Когда нужно отобразить огромное число в пользовательском интерфейсе (скажем, количество лайков или подписчиков), зачастую показывать число полностью не имеет смысла. Гораздо удобнее использовать агрегированное представление в виде "12M" или "1.5K".
Данное расширение позволяет получить в виде аббревиатуры числа вплоть до квадриллиона. Если кратко, то логика такая:
1. Есть список аббревиатур "KMBTQ". Проходимся по нему с конца, потому что представление должно быть как можно компактнее.
2. Для каждой аббревиатуры определяем фактор. Для тысяч это ЧИСЛО/10^3 (10 в степени 3).
3. Если фактор меньше нуля, число слишком маленькое для этой аббревиатуры, поэтому двигаемся дальше.
4. Если фактор больше нуля, значит к фактору добавляем нужную аббревиатуру и получаем результат.
Source
#handyExtensions #int #intermediate
#MockInterview
Вопрос: Как можно увеличить зону нажатия в UIButton, чтобы соответствовать HIG? 💬
Ответ: Есть два способа решения этой задачи. Первый – это использование contentEdgeInsets. Больше размер = больше зона нажатия. В этом подходе важно учитывать, что мы просто увеличиваем размер кнопки. Если у нас есть заданный frame или же установленные constraint, то UIButton будет просто сжимать текст / изображение, и эффекта это не даст.
Второй подход – сделать свой наследник UIButton и переопределить point-inside метод. Это позволит нам увеличить зону нажатия без изменения самого размера кнопки. Правда, если кнопка вложенная в какой-то parent view, то увеличить зону нажатия за его пределы не выйдет.
Объяснение: Вопрос очень базовый, но почему-то всех всегда сбивает с толку слово HIG. А это просто аббревиатура Human Interface Guidelines, где Apple пишет, что ваша кнопка должна быть минимум 44 пикселя (кстати, запомните это число, некоторые компании умудряются задавать даже такой вопрос).
По сути, подхода для решения поставленной задачи два. Если нужно увеличить зону, и есть возможность быстро поменять размер кнопки, – contentEdgeInsets. Если ситуация сложнее, например, кнопка в UIStackView, – наследование и переопределение point(point:with).
#UIButton #basic
Вопрос: Как можно увеличить зону нажатия в UIButton, чтобы соответствовать HIG? 💬
Ответ: Есть два способа решения этой задачи. Первый – это использование contentEdgeInsets. Больше размер = больше зона нажатия. В этом подходе важно учитывать, что мы просто увеличиваем размер кнопки. Если у нас есть заданный frame или же установленные constraint, то UIButton будет просто сжимать текст / изображение, и эффекта это не даст.
Второй подход – сделать свой наследник UIButton и переопределить point-inside метод. Это позволит нам увеличить зону нажатия без изменения самого размера кнопки. Правда, если кнопка вложенная в какой-то parent view, то увеличить зону нажатия за его пределы не выйдет.
Объяснение: Вопрос очень базовый, но почему-то всех всегда сбивает с толку слово HIG. А это просто аббревиатура Human Interface Guidelines, где Apple пишет, что ваша кнопка должна быть минимум 44 пикселя (кстати, запомните это число, некоторые компании умудряются задавать даже такой вопрос).
По сути, подхода для решения поставленной задачи два. Если нужно увеличить зону, и есть возможность быстро поменять размер кнопки, – contentEdgeInsets. Если ситуация сложнее, например, кнопка в UIStackView, – наследование и переопределение point(point:with).
#UIButton #basic
Опциональное декодирование элементов массива с помощью Decodable
Сегодня мы разберем случай, когда нужно отобразить массив данных с сервера, даже если некоторые элементы этого массива декодировать не удается. Предположим, в приложении есть секция (жанр музыки). В этой секции есть много разных элементов (песен). Если случится так, что какая-то песня придет с сервера с ошибкой (или с ней что-то будет не так), мы все равно сможем отобразить секцию без проблемного трека.
Для этого нам понадобится создать дженерик класс FailableDecodable с типом, который нужно будет десериализовать. Далее, используя singleValueContainer, получаем контейнер с декодера и пробуем получить нужную нам модель с помощью try? container.decode(Base.self).
Чтобы выполнить само декодирование элементов массива, вместо обычного типа данных, указываем тип в обертке с FailableDecodable и проходимся по нему с помощью compactMap, получая переменную base.
Таким образом, сначала мы получили массив с опциональными элементами, где могут встречаться nil, а дальше профильтровали этот массив, оставив только non-nil значения.
Source
#tips #decodable #intermediate
Сегодня мы разберем случай, когда нужно отобразить массив данных с сервера, даже если некоторые элементы этого массива декодировать не удается. Предположим, в приложении есть секция (жанр музыки). В этой секции есть много разных элементов (песен). Если случится так, что какая-то песня придет с сервера с ошибкой (или с ней что-то будет не так), мы все равно сможем отобразить секцию без проблемного трека.
Для этого нам понадобится создать дженерик класс FailableDecodable с типом, который нужно будет десериализовать. Далее, используя singleValueContainer, получаем контейнер с декодера и пробуем получить нужную нам модель с помощью try? container.decode(Base.self).
Чтобы выполнить само декодирование элементов массива, вместо обычного типа данных, указываем тип в обертке с FailableDecodable и проходимся по нему с помощью compactMap, получая переменную base.
Таким образом, сначала мы получили массив с опциональными элементами, где могут встречаться nil, а дальше профильтровали этот массив, оставив только non-nil значения.
Source
#tips #decodable #intermediate
Как использовать tableHeaderView вместе с auto-layout?
Казалось бы, задача тривиальная, но на деле все немного сложнее. Для ее решения нам понадобится создать два метода: setTableHeaderView (1), updateTableHeaderViewIfNeeded (2). Логика следующая:
1. Мы создаем width constraint, где ширина tableHeaderView равна ширине самой tableView. Это позволит таблице получить нужный размер, когда мы будем вызывать layoutIfNeeded. Дополнительно мы центрируем наш хедер и крепим его вверху таблицы.
2. Реагируем на изменения размера в случаях вроде поворота девайса. Для этого позволяем tableView управлять frame самостоятельно, точно так же, как для ячеек. Достигается это с помощью beginUpdates/endUpdates.
Метод setTableHeaderView вызываем, когда делаем layout для нашего UI - viewDidLoad, а updateTableHeaderViewIfNeeded в viewDidLayoutSubviews.
Source
#tips #tableView #basic
Казалось бы, задача тривиальная, но на деле все немного сложнее. Для ее решения нам понадобится создать два метода: setTableHeaderView (1), updateTableHeaderViewIfNeeded (2). Логика следующая:
1. Мы создаем width constraint, где ширина tableHeaderView равна ширине самой tableView. Это позволит таблице получить нужный размер, когда мы будем вызывать layoutIfNeeded. Дополнительно мы центрируем наш хедер и крепим его вверху таблицы.
2. Реагируем на изменения размера в случаях вроде поворота девайса. Для этого позволяем tableView управлять frame самостоятельно, точно так же, как для ячеек. Достигается это с помощью beginUpdates/endUpdates.
Метод setTableHeaderView вызываем, когда делаем layout для нашего UI - viewDidLoad, а updateTableHeaderViewIfNeeded в viewDidLayoutSubviews.
Source
#tips #tableView #basic
Асинхронные скрипты на Swift
Да, на Swift можно писать скрипты и, используя некоторые хитрости, делать это достаточно эффективно. А с добавлением executableTarget в SPM задача стала еще проще.
Проблема возникает тогда, когда вы пытаетесь сделать скрипт асинхронным (например, получить или обновить какие-то данные в сети). В таком случае нужно заставить скрипт ждать выполнения асинхронной задачи и только после этого завершать работу. В этом нам поможет RunLoop. Обычно, когда мы пишем приложения под iOS или macOS, система сама контролирует процесс создания RunLoop, но для скриптов мы должны сделать это самостоятельно.
Сегодня я хотел бы поделиться небольшой, но полезной библиотекой SwiftScriptRunner, которая реализует своего рода мьютекс, предотвращая завершение программы. Механизм достаточно простой: счетчик, на основе которого мы стартуем бесконечный цикл while, в котором запускаем RunLoop.current на 0.1 секунды. Как только счетчик становится равен 0, скрипт завершает работу.
Source / SwiftScriptRunner
#shareLibrary #scripts #advanced
Да, на Swift можно писать скрипты и, используя некоторые хитрости, делать это достаточно эффективно. А с добавлением executableTarget в SPM задача стала еще проще.
Проблема возникает тогда, когда вы пытаетесь сделать скрипт асинхронным (например, получить или обновить какие-то данные в сети). В таком случае нужно заставить скрипт ждать выполнения асинхронной задачи и только после этого завершать работу. В этом нам поможет RunLoop. Обычно, когда мы пишем приложения под iOS или macOS, система сама контролирует процесс создания RunLoop, но для скриптов мы должны сделать это самостоятельно.
Сегодня я хотел бы поделиться небольшой, но полезной библиотекой SwiftScriptRunner, которая реализует своего рода мьютекс, предотвращая завершение программы. Механизм достаточно простой: счетчик, на основе которого мы стартуем бесконечный цикл while, в котором запускаем RunLoop.current на 0.1 секунды. Как только счетчик становится равен 0, скрипт завершает работу.
Source / SwiftScriptRunner
#shareLibrary #scripts #advanced