SWIFTER | Блог про Swift
274 subscribers
4 photos
30 links
Swift для каждого на простом и понятном языке. Уроки программирования с интересными кейсами из реальных проектов, без воды и сложных терминов.
Download Telegram
Better self-executing closures

Очень часто мы используем self-executing closure для настройки объектов в Swift. В основном именно во view слое, реже – в других частях код-базы. И хотя такие closure невероятно удобны, их можно улучшить: уменьшить размер, не ухудшив читаемость кода.

Сегодня хотел бы рассказать вам о функции-утилите, которую я повсеместно использую в своих проектах. Функция configure принимает любой объект или значение, используя ключевое слово inout, модифицирует его по ссылке и возвращает.

Звучит достаточно просто? Так и есть. Я добавил еще атрибут discardableResult, чтобы в случае необходимости игнорировать возвращаемое значение, и rethrows, чтобы не использовать try/catch для closure, которые не выбрасывают ошибки.

Функцию можно объявить глобально в проекте или использовать мой SDK: PimineUtilities, где эта функция уже реализована.

Source / PimineSDK
#utilities #closures #intermediate
Что такое discardableResult и как использовать этот атрибут?

Во время написания функций или методов в Swift мы в некоторых случаях хотим игнорировать возвращаемое значение, а в других – все же иметь возможность обработать его. Если попытаться вызвать метод, который возвращает значение, и никак его не обработать, получим предупреждение "Result of call to 'foo()' is unused".

Атрибут discardableResult позволяет убрать данное предупреждение. В случае правильного использования эта небольшая функция (о которой, тем не менее, стоит знать) улучшит чистоту вашего кода и позволит вам не использовать нижнее подчеркивание, чтобы игнорировать результат.

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

Source
#languageGuide #attributes #basic
Что такое параметры inout?

Когда мы передаем value типы в качестве аргументов в функцию, они статичны – менять их нельзя. Было бы удобно иметь возможность модифицировать данные значения. К счастью, у Swift для этого есть решение: ключевое слово inout, которое используется перед типом параметра в связке с '&' перед аргументом. Это позволит нам модифицировать значение внутри функции.

На самом деле, мы не модифицируем значением напрямую. Такое поведение называется "copy-in copy-out" или же "call by value result" и работает следующим образом:
1. Когда мы вызываем функцию, значение аргумента копируется.
2. Дальше внутри функции копия модифицируется.
3. По возращению функции Swift присваивает модифицированное значение оригинальному аргументу.

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

Source
#languageGuide #inout #advanced
Как декодировать property list используя Decodable?

Property list
, обычно сокращенно plist, представляет собой XML-файл, содержащий данные в формате "ключ-значение". Вы можете использовать его в своих приложениях для iOS в качестве простого хранилища данных. Эта функция-утилита позволит вам задекодить данные в нужный удобный вам тип, используя Decodable.

Source
#handyExtensions #plist #basic
Как использовать ключевое слово rethrows?

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

Ключевое слово rethrows используется, когда вы пишете функцию (назовем ее A), которая принимает другую функцию в качестве параметра (назовем ее B). Rethrows делает так, что если функция B выбрасывает ошибки, тогда и A будет выбрасывать ошибки. Если функция B не выбрасывает ошибки, тогда и A этого делать не будет.

Какое преимущество мы получаем? Rethrows позволяет убрать лишние try/catch в случаях, где они не нужны.

Возьмем стандартные 'map', 'filter', 'forEach' для массивов. Когда вы внутри замыкания помечаете что-то как try, Swift просит вас добавить try еще и для вызова "Call can throw but is not marked with 'try'". Если внутри замыкания ничего ошибку выбрасывать не будет, тогда и целый вызов помечать try не нужно.

Данное поведение во всех описанных выше методах реализовано‌‌‎ с помощью rethrows‎.‌‌‎​

Source
#languageGuide #rethrows #advanced
Channel photo updated
Привет, будем знакомиться?👋🏻

Меня зовут Ден Андрейчук, и я – iOS разработчик. Работаю в сфере мобильной разработки на Swift уже 4 года, за это время успел стать senior developer, решить множество сложных задач, реализовать десятки проектов и набраться опыта.

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

– здоровом программировании;
– правильном планировании рабочего времени;
– работе на open-source;
– продвижении разработчика по карьерной лестнице;
– важности грамотно написанного резюме;
– использовании техники помодоро и йоги и многом другом.

Оставайтесь со мной, будет познавательно! 😉

Instagram
LinkedIn
Github
Telegram
Как использовать String в качестве ошибок?

Обычно, чтобы сообщать о том, что операция завершилась с ошибкой, в Swift используется протокол Error. Когда мы проектируем чистое API, обычной практикой для выполнения данной цели является создание собственного error enum, в котором прописываются нужные варианты ошибок под конкретный функционал.

Но что делать, если мы хотим получить простое решение для случаев, когда ошибки единичные и смысла создавать отдельный enum нет?

Тогда можно реализовать LocalizedError для String и использовать строку в качестве ошибки. Такой вариант идеально подойдет для возвращение простых, user-facing ошибок.

Source
#handyExtensions #error #basic
Как легко cделать глубокую копию (deep-copy) объекта в Swift?

В Swift есть два основных типа данных: объекты (reference types) и структуры (value types). Одно из ключевых различий между value и reference типами сводится к копированию: две переменные могут указывать на один и тот же объект, поэтому если вы попытаетесь изменить одну переменную, изменения коснутся и второй. Если вы попытаетесь проделать этот же трюк со структурами, то обнаружите, что здесь изменения копии не влияют на оригинал.

Теперь вопрос: а как сделать так, чтобы изменение в одной части проекта не влияло на другие в reference типах? Для этого нам нужно сделать глубокую копию (deep-copy) объекта. Одним из вариантов решения является использование протокола NSCopying. И хотя этот способ имеет место быть, он создает много шаблонного (boilerplate) кода.

Сегодня я хочу показать вам, как для решения этой задачи можно использовать Codable. Идея достаточно простая: сначала мы кодируем объект в Data, а дальше из Data в нужный нам тип. Поскольку Data является value типом в Swift, при копировании выполняется deep-copy по умолчанию. На выходе мы получим новый объект с теми же данными, что и оригинал.

Ссылка
#tips #codable #intermediate
Как копировать текст в буфер обмена, используя UIPasteboard?

Вы можете писать в буфер обмена iOS и читать из него с помощью класса UIPasteboard. Для того, чтобы воспользоваться глобальным системным буфером, нужно использовать константу general. Это позволит обмениваться данными между всеми приложениями. Обычно пользователи взаимодействуют с системным буфером, используя "вырезать", "скопировать", "вставить" на выбранном контенте в UI.

В UIPasteboard можно хранить String, UIImage, URL, UIColors, но чаще всего вы будете использовать именно String. Чтобы записать или прочитать строку, достаточно просто считать или присвоить что-то переменной string.

Ссылка
#tips #pasteboard #basic
Что нового в Xcode 13?

▪️Новый вид значка у файлов в навигационной панели и отсутствие расширения по умолчанию.

▪️Распознавание типа данных и автоматический импорт нужной библиотеки.

▪️Масштабное обновление функционала Git: возможность сравнивать изменения, открывать pull request, выполнять код-ревью и приглашать ревьюеров.

▪️Автоматическое заполнение всех кейсов перечисления при использовании switch, автозаполнение массивов.

▪️Автозаполнение при использовании привязки для опционалов (if let).

▪️ Интеграция Xcode Cloud и поддержка разметки документации DocC, клавиатуры Vim.

▪️Возможность поставить breakpoint в любом месте одной строчки кода (column breakpoint).

▪️Новый способ отображения ошибок с помощью минимизированного режима.

#news #xcode
Взаимозаменяемое использование типов CGFloat и Double

SE-0307 в Swift 5.5 добавляет небольшое, но тем не менее очень полезное нововведение: компилятор будет автоматически уметь конвертировать между CGFloat и Double там где это нужно. Это значит, что мы сможем выполнять такие операции как умножение и деление без приведение типов.

Swift будет всегда отдавать предпочтение Double, чтобы предотвратить потерю точности. Более того, все описанное выше реализовано путем неявного использование нужного инициализатора для конвертации. Это значит, что это нововведение не меняет никакое с существующих API.

Source
#tips #core #basic
Привет, СВИФТЕРЫ👋🏻

Врываемся в ваше воскресенье с крутой новостью! Теперь на нашем канале доступны комментарии к постам.

Задавайте любые вопросы, пишите пожелания к контенту, общайтесь между собой и учите Swift вместе😉

Ну что, пообщаемся?
Как добавить Pull-to-Refresh в UITableView или UICollectionView?

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
Как удалить десятичную дробь из числа с плавающей запятой, если она равна 0?

Это простое расширение убирает десятичную дробь из числа с плавающей запятой, если она равна 0. Это пригодится в тех случаях, когда нам нужно сделать красивый вывод числа где-то в пользовательском интерфейсе. Мы используем truncatingRemainder (тот же %), чтобы найти остаток от деления. Если оно равно нулю, то убираем плавающую точку, форматируя строку в виде "%.0f", в противном же случае просто конвертируем Double в String без каких-либо изменений.

Source
#handyExtensions #double #basic