Разное

Свифт что: Как работает система SWIFT — система межбанковских денежных переводов

25.08.1982

Содержание

Что будет, если Россию все же отключат от SWIFT

Угроза отключения российских банков от SWIFT периодически возникает с 2014 г., и это один из наиболее серьезных санкционных рисков. Что произойдет в реальности, если эта угроза все-таки реализуется?

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

Во-вторых, такой сценарий неизбежно приводит к валютному шоку. Доллар и евро снова устремятся тестировать самые высокие уровни. Что предпримет в ответ ЦБ? Снова, как в 2014 г. , будет повышать ключевую ставку в несколько раз? Или «кидать в топку» валютные запасы? В любом случае девальвация рубля приведет еще к одному витку роста стоимости импортных товаров, а это и еще один инфляционный риск. И удар по имиджу власти.

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

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

Четвертое: вполне вероятны в этом случае сбои в работе карт основных международных платежных систем – Visa и Mastercard. Несмотря на то что для обеспечения расчетов по картам всегда есть резерв на спецсчетах, такой риск тоже не стоит игнорировать.

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

При этом для внутренних расчетов отключение от SWIFT будет малозаметным. Система быстрых платежей работает для физических лиц практически идеально. Доля сообщений через созданную Банком России систему передачи финансовых сообщений, по словам зампредседателя ЦБ Ольги Скоробогатовой, по итогам 2020 г. достигла 20% от внутрироссийского трафика и продолжает быстро расти. Общее число участников этой системы достигло 400, среди которых банки из Армении, Белоруссии, Казахстана, Киргизии и даже Германии и Швейцарии. Наконец, платежная система «Мир» в целом вполне может обеспечить бесперебойную работу карт внутри страны, если будут проблемы с Visa и Mastercard.

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

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

Существуют ли варианты обхода отключения от SWIFT, если оно будет принято? Внутри страны и на постсоветском пространстве больших проблем возникнуть не должно. Бесперебойность международных расчетов во многом будет зависеть от позиции Европы, Китая и Индии, у которых есть свои аналоги SWIFT. Международные карточки могут быть заменены на китайскую платежную систему UnionPay, активно продвигаемую в последние несколько лет, или другие аналоги. Ну и, наконец, новый стимул в развитии получат цифровые валюты, для расчетов которыми SWIFT вообще не нужна. Финансовые рынки на пике шока будут поддержаны ЦБ и институтами развития. Процессы перехода будут непростыми и небыстрыми, но очевидно, что система сможет адаптироваться.

Лоббисты в США и Европе, в том числе финансовые группы, промышленные конгломераты и сама SWIFT, сейчас очень активно борются за то, чтобы сценарий отключения России не реализовался ни в каком виде – ни в жестком, ни в мягком. Несмотря на все ограничения и санкции, Россия и ее финансовая система остаются сильно интегрированными в мировую экономику. Транзакций много, да и в целом отключение от SWIFT России в отличие от Ирана – решение крайне непопулярное в деловых кругах Запада. Поэтому, понимая достаточно масштабные негативные последствия такого сценария, все-таки не будем считать его очень вероятным.

Основы — SwiftBook

Swift — новый язык программирования для разработки приложений под iOS, macOS, watchOS и tvOS. Несмотря на это, многие части Swift могут быть вам знакомы из вашего опыта разработки на C и Objective-C.

Swift предоставляет свои собственные версии фундаментальных типов C и Objective-C, включая Int для целых чисел, Double и Float для значений с плавающей точкой, Bool для булевых значений, String для текста. Swift также предоставляет мощные версии трех основных типов коллекций, Array, Set и Dictionary, как описано в разделе Типы коллекций.

Подобно C, Swift использует переменные для хранения и обращения к значениям по уникальному имени. Swift также широко использует переменные, значения которых не могут быть изменены. Они известны как константы, и являются гораздо более мощными, чем константы в C. Константы используются в Swift повсеместно, чтобы сделать код безопаснее и чище в случаях, когда вы работаете со значениями, которые не должны меняться.

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

Swift также включает опциональные типы, которые позволяют работать с отсутствующими значениями. Опциональные значения говорят либо «здесь есть значение, и оно равно х», либо «здесь нет значения вообще». Опциональные типы подобны использованию nil с указателями в Objective-C, но они работают со всеми типами, не только с классами. Опциональные значения безопаснее и выразительнее чем nil указатели в Objective-C, и находятся в сердце многих наиболее мощных особенностей Swift.

Swift — язык типобезопасный, что означает, что Swift помогает вам понять, с какими типами значений ваш код может работать. Если кусок вашего кода ожидает String, безопасность типов не даст вам передать ему Int по ошибке. Кроме того, безопасность типов не позволит вам случайно передать опциональный String куску кода, который ожидает неопциональный String. Безопасность типов позволяет вам улавливать и исправлять ошибки как можно раньше в процессе разработки.

Константы и переменные связывают имя (например, maximumNumberOfLoginAttempts или welcomeMessage) со значением определенного типа (например, число 10 или строка «Hello»). Значение константы не может быть изменено после его установки, тогда как переменной может быть установлено другое значение в будущем.

Объявление констант и переменных

Константы и переменные должны быть объявлены, перед тем как их использовать. Константы объявляются с помощью ключевого слова let, а переменные с помощью var. Вот пример того, как константы и переменные могут быть использованы для отслеживания количества попыток входа, которые совершил пользователь:

let maximumNumberOfLoginAttempts = 10
var currentLoginAttempt = 0

Этот код можно прочесть как:

«Объяви новую константу с именем maximumNumberOfLoginAttempts, и задай ей значение 10. Потом, объяви новую переменную с именем currentLoginAttempt, и задай ей начальное значение 0.»

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

Вы можете объявить несколько констант или несколько переменных на одной строке, разделяя их запятыми:

var x = 0.0, y = 0.0, z = 0.0
Заметка

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

Аннотация типов

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

Этот пример добавляет обозначение типа для переменной с именем welcomeMessage, чтобы обозначить, что переменная может хранить String:

var welcomeMessage: String

Двоеточие в объявлении значит «…типа…», поэтому код выше может быть прочитан как:

«Объяви переменную с именем welcomeMessage, тип которой будет String»

Фраза «тип которой будет String» означает «может хранить любое String значение». Представьте, что словосочетание «тип которой будет такой-то» означает — значение, которое будет храниться.

Теперь переменной welcomeMessage можно присвоить любое текстовое значение, без каких либо ошибок:

welcomeMessage = "Hello"

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

var red, green, blue: Double
Заметка

Редко когда вам понадобится обозначать тип на практике. Когда вы даете начальное значение константе или переменной на момент объявления, Swift всегда может вывести тип, который будет использовать в константе или переменной. Это описано в Строгая типизация и Вывод типов. В примере welcomeMessage выше, не было присвоения начального значения, так что тип переменной welcomeMessage указывается с помощью обозначения типа вместо того, чтобы вывести из начального значения.

Название констант и переменных

Вы можете использовать почти любые символы для названий констант и переменных, включая Unicode-символы:

let π = 3.14159
let 你好 = "你好世界"
let ?? = "dogcow"

Имена констант и переменных не могут содержать пробелы, математические символы, стрелки, приватные (или невалидные) кодовые точки Unicode, а так же символы отрисовки линий или прямоугольников. Так же имена не могут начинаться с цифр, хотя цифры могут быть включены в имя в любом другом месте. Если вы объявили константу или переменную определенного типа, то вы не можете объявить ее заново с тем же именем или заставить хранить внутри себя значение другого типа. Также вы не можете изменить константу на переменную, а переменную на константу.

Заметка

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

Вы можете изменить значение переменной на другое значение совместимого типа. В примере ниже значение friendlyWelcome изменено с “Hello!” на “Bonjour!”:

var friendlyWelcome = “Hello!”
friendlyWelcome = “Bonjour!”
// теперь friendlyWelcome имеет значение “Bonjour!”

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

let languageName = "Swift"
languageName = "Swift++"
// Это ошибка компилляции: languageName cannot be changed (значение languageName не может быть изменено).

Печать констант и переменных

Вы можете напечатать текущее значение константы или переменной при помощи функции print(_:separator:terminator:):

print(friendlyWelcome)
// Выведет "Bonjour!"

Функция print(_:separator:terminator:) является глобальной, которая выводит одно или более значений в подходящем виде. В Xcode, например, функция print(_:separator:terminator:) выводит значения в консоль. Параметры separator и terminator имеют дефолтные значения, так что при использовании функции их можно просто пропустить. По умолчанию функция заканчивает вывод символом переноса строки. Чтобы вывести в консоль значения без переноса на новую строку, вам нужно указать пустую строку в параметре terminator, например, print(someValue, terminator: «»). Для получения дополнительной информации по дефолтным значениям параметров обратитесь в раздел «Значения по умолчанию для параметров».

Swift использует интерполяцию строки для включения имени константы или переменной в качестве плейсхолдера внутри строки, что подсказывает Swift подменить это имя на текущее значение, которое хранится в этой константе или переменной. Поместите имя константы или переменной в круглые скобки, а затем добавьте обратный слеш (\) перед открывающей  скобкой:

print("Текущее значение friendlyWelcome равно \(friendlyWelcome)")
// Выведет "Текущее значение friendlyWelcome равно Bonjour!"
Заметка

Все опции, которые вы можете использовать в интерполяции строки вы сможете найти в разделе «Интерполяция строк».

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

Комментарии в Swift очень похожи на комментарии в C. Однострочные комментарии начинаются с двух слешей (//):

// это комментарий

Вы также можете написать многострочные комментарии, которые начинаются со слеша и звездочки (/*) и заканчиваются звездочкой, за которой следует слеш (*/):

/* это тоже комментарий,
но написанный на двух строках */

В отличие от многострочных комментариев в C, многострочные комментарии в Swift могут быть вложены в другие многострочные комментарии. Вы можете написать вложенные комментарии, начав многострочный блок комментариев, а затем, начать второй многострочный комментарий внутри первого блока. Затем второй блок закрывается, а за ним закрывается первый блок:

/* это начало первого многострочного комментария
/* это второго, вложенного многострочного комментария */
это конец первого многострочного комментария */

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

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

let cat = "?"; print(cat)
// Выведет "?"

Integer (целое число) — это число, не содержащее дробной части, например, как 42 и -23. Целые числа могут быть либо знаковыми (положительными, ноль или отрицательными) либо беззнаковыми (положительными или ноль).

Swift предусматривает знаковые и беззнаковые целые числа в 8, 16, 32 и 64 битном форматах. Эти целые числа придерживаются соглашения об именах, аналогичных именам в C, в том, что 8-разрядное беззнаковое целое число имеет тип Uint8, а 32-разрядное целое число имеет тип Int32. Как и все типы в Swift, эти типы целых чисел пишутся с заглавной буквой.

Границы целых чисел

Вы можете получить доступ к минимальному и максимальному значению каждого типа целого числа с помощью его свойств min и max:

let minValue = UInt8.min // minValue равен 0, а его тип UInt8
let maxValue = UInt8.max // maxValue равен 255, а его тип UInt8

Тип значения этих свойств соответствует размеру числа (в примере выше этот тип UInt8) и поэтому может быть использован в выражениях наряду с другими значениями того же типа.

Int

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

  • На 32-битной платформе, Int того же размера что и Int32
  • На 64-битной платформе, Int того же размера что и Int64

Если вам не нужно работать с конкретным размером целого числа, всегда используйте в своем коде Int для целых чисел. Это придает коду логичность и совместимость. Даже на 32-битных платформах, Int может хранить любое значение в пределах -2 147 483 648 и 2 147 483 647, а этого достаточно для многих диапазонов целых чисел.

UInt

Swift также предусматривает беззнаковый тип целого числа — UInt, который имеет тот же размер что и разрядность системы:

  • На 32-битной платформе, UInt того же размера что и UInt32
  • На 64-битной платформе, UInt того же размера что и UInt64
Заметка

Используйте UInt, только когда вам действительно нужен тип беззнакового целого с размером таким же, как разрядность системы. Если это не так, использовать Int предпочтительнее, даже когда известно, что значения будут неотрицательными. Постоянное использование Int для целых чисел способствует совместимости кода, позволяет избежать преобразования между разными типами чисел, и соответствует выводу типа целого числа, как описано в Строгая типизация и Вывод Типов.

Число с плавающей точкой — это число с дробной частью, например как 3.14159, 0.1, и -273.15.

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

  • Double — представляет собой 64-битное число с плавающей точкой. Используйте его когда число с плавающей точкой должно быть очень большим или чрезвычайно точным
  • Float — представляет собой 32-битное число с плавающей точкой. Используйте его, когда значение не нуждается в 64-битной точности.
Заметка

Double имеет точность минимум 15 десятичных цифр, в то время как точность Float может быть всего лишь 6 десятичных цифр. Соответствующий тип числа с плавающей точкой используется в зависимости от характера и диапазона значений, c которыми вы должны работать в коде. В случаях, где возможно использование обоих типов, предпочтительным считается Double.

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

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

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

Благодаря выводу типов, Swift требует гораздо меньше объявления типов, чем языки, такие как C или Objective-C. Константам и переменным все же нужно присваивать тип, но большая часть работы с указанием типов будет сделана за вас.

Вывод типов особенно полезен, когда вы объявляете константу или переменную с начальным значением. Часто это делается путем присвоения литерального значения (или литерала) к константам или переменным в момент объявления​​. (Литеральное значение — значение, которое появляется непосредственно в исходном коде, например как 42 и 3,14159 в примерах ниже.)

Например, если вы присваиваете литеральное значение 42 к новой константе не сказав какого она типа, Swift делает вывод, что вы хотите чтобы константа была Int, потому что вы присвоили ей значение, которое похоже на целое число:

let meaningOfLife = 42
// meaningOfLife выводится как тип Int

Точно так же, если вы не указали тип для литерала с плавающей точкой, Swift делает вывод, что вы хотите создать Double:

let pi = 3.14159
// pi выводится как тип Double

Swift всегда выбирает Double (вместо Float), когда выводит тип чисел с плавающей точкой.

Если объединить целые литералы и литералы с плавающей точкой в одном выражении, в этом случае тип будет выводиться как Double:

let anotherPi = 3 + 0.14159
// anotherPi тоже выводится как тип Double

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

Числовые литералы могут быть написаны как:

  • Десятичное число, без префикса
  • Двоичное число, с префиксом 0b
  • Восьмеричное число, с префиксом 0o
  • Шестнадцатеричное число, с префиксом 0x

Все эти литералы целого числа имеют десятичное значение 17:

let decimalInteger = 17
let binaryInteger = 0b10001 // 17 в двоичной нотации
let octalInteger = 0o21 // 17 в восмеричной нотации
let hexadecimalInteger = 0x11 // 17 в шестнадцатеричной нотации

Литералы с плавающей точкой могут быть десятичными (без префикса) или шестнадцатеричными (с префиксом 0x). Они всегда должны иметь число (десятичное или шестнадцатеричное) по обе стороны от дробной точки. Они также могут иметь экспоненту, с указанием в верхнем или нижнем регистре е для десятичных чисел с плавающей точкой, или в верхнем или нижнем регистре р для шестнадцатеричных чисел с плавающей точкой.

Для десятичных чисел с показателем степени ехр, базовое число умножается на 10exp:

  • 1.25e2 означает 1.25 × 102, или 125.0.
  • 1.25e-2 означает 1.25 × 10-2, или 0.0125.

Для шестнадцатеричных чисел с показателем степени ехр, базовое число умножается на 2exp:

  • 0xFp2 означает 15 × 22, или 60.0.
  • 0xFp-2 означает 15 × 2-2, или 3.75.

Все эти числа с плавающей точкой имеют десятичное значение 12.1875:

let decimalDouble = 12.1875
let exponentDouble = 1.21875e1
let hexadecimalDouble = 0xC.3p0

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

let paddedDouble = 000123.456
let oneMillion = 1_000_000
let justOverOneMillion = 1_000_000.000_000_1

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

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

Преобразования целых чисел

Диапазон значений, который может храниться в целочисленных константах и переменных, различен для каждого числового типа. Int8 константы и переменные могут хранить значения между -128 и 127, тогда как UInt8 константы и переменные могут хранить числа между 0 и 255. Если число не подходит для переменной или константы с определенным размером, выводится ошибка во время компиляции:

let cannotBeNegative: UInt8 = -1
// UInt8 не может хранить отрицательные значения, поэтому эта строка выведет ошибку
let tooBig: Int8 = Int8.max + 1
// Int8 не может хранить число больше своего максимального значения,
// так что это тоже выведет ошибку

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

Чтобы преобразовать один числовой тип в другой, необходимо создать новое число желаемого типа из существующего значения. Ниже, в примере, константа twoThousand имеет тип UInt16, тогда как константа one — UInt8. Сложить их напрямую не получится, потому что они разного типа. Вместо этого, в примере вызывается функция UInt16(one) для создания нового числа UInt16 из значения константы one:

let twoThousand: UInt16 = 2_000
let one: UInt8 = 1
let twoThousandAndOne = twoThousand + UInt16(one)

Теперь, из-за того, что обе части сложения имеют тип UInt16 — операция сложения допустима. Для конечной константы (twoThousandAndOne) выведен тип UInt16, потому что это сложение двух UInt16 значений.

НазваниеТипа(начальноеЗначение) — стандартный способ вызвать инициализатор типов Swift и передать начальное значение. Честно говоря, у UInt16 есть инициализатор, который принимает UInt8 значение, и, таким образом, этот инициализатор используется, чтобы создать новый UInt16 из существующего UInt8. Здесь вы не можете передать любой тип, однако это должен быть тип, для которого у UInt16 есть инициализатор. Расширение существующих типов с помощью создания инициализаторов, которые принимают новые типы (включая объявление вашего типа) рассматривается в главе Расширения.

Преобразования целых чисел и чисел с плавающей точкой

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

let three = 3
let pointOneFourOneFiveNine = 0.14159
let pi = Double(three) + pointOneFourOneFiveNine
// pi равно 3.14159, и для него выведен тип Double

Здесь, значение константы three используется для создания нового значения типа Double, так что обе части сложения имеют один тип. Без этого преобразования сложение не будет проходить. Обратное преобразование числа с плавающей точкой в целое число тоже должно происходить явно. Так что тип целого числа может быть инициализирован с помощью Double и Float значений:

let integerPi = Int(pi)
// integerPi равен 3, и для него выведен тип Int

Числа с плавающей точкой всегда урезаются, когда вы используете инициализацию целого числа через этот способ. Это означает, что 4.75 будет 4, а -3.9 будет -3.

Заметка

Правила объединения числовых констант и переменных отличается от правил числовых литералов. Литеральное значение 3 может напрямую сложиться с литеральным значением 0.14159, потому что числовые литералы сами по себе не имеют явного типа. Их тип выводится только в момент оценки значения компилятором.

Псевдонимы типов задают альтернативное имя для существующего типа. Можно задать псевдоним типа с помощью ключевого слова typealias.

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

typealias AudioSample = UInt16

После того как вы один раз задали псевдоним типа, вы можете использовать псевдоним везде, где вы хотели бы его использовать

var maxAmplitudeFound = AudioSample.min
// maxAmplitudeFound теперь 0

Здесь AudioSample определен как псевдоним для UInt16. Поскольку это псевдоним, вызов AudioSample.min фактически вызовет UInt16.min, что показывает начальное значение 0 для переменной maxAmplitudeFound.

В Swift есть простой логический тип Bool. Этот тип называют логическим, потому что он может быть только true или false. Swift предусматривает две логические константы, true и false соответственно:

let orangesAreOrange = true
let turnipsAreDelicious = false

Типы для orangesAreOrange и turnipsAreDelicious были выведены как Bool, исходя из того факта, что мы им присвоили логические литералы. Так же как с Int и Double в предыдущих главах, вам не нужно указывать константы или переменные как Bool, если при создании вы присвоили им значения true или false. Вывод типов помогает сделать код Swift кратким и читабельным тогда, когда вы создаете константы или переменные со значениями которые точно известны.

Логические значения очень полезны когда вы работаете с условными операторами, такими как оператор if:

if turnipsAreDelicious {
 print("Mmm, tasty turnips!")
} else {
 print("Eww, turnips are horrible.")
}
// Выведет "Eww, turnips are horrible."

Условные операторы, такие как оператор if детально рассматриваются в главе Управление потоком.

Строгая типизация Swift препятствует замене значения Bool на не логическое значение. Следующий пример выведет ошибку компиляции:

let i = 1
if i {
 // этот пример не скомпилируется, и выдаст ошибку компиляции
}

Тем не менее, альтернативный пример ниже правильный:

let i = 1
if i == 1 {
 // этот пример выполнится успешно
}

Результат сравнения i == 1 имеет тип Bool, и поэтому этот второй пример совершает проверку типов. Такие сравнения как i == 1 обсуждаются в главе Базовые операторы.

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

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

В данном примере (404, «Not Found») это кортеж, который описывает код HTTP статуса. Код HTTP статуса — особое значение, возвращаемое веб-сервером каждый раз, когда вы запрашиваете веб-страницу. Код статуса 404 Not Found возвращается, когда вы запрашиваете страницу, которая не существует.

let http404Error = (404, "Not Found")
// http404Error имеет тип (Int, String), и равен (404, "Not Found")

Чтобы передать код статуса, кортеж (404, «Not Found») группирует вместе два отдельных значения Int и String: число и понятное человеку описание. Это может быть описано как «кортеж типа (Int, String)».

Вы можете создать кортеж с любой расстановкой типов, и они могут содержать сколько угодно нужных вам типов. Ничто вам не мешает иметь кортеж типа (Int, Int, Int), или типа (String, Bool), или же с любой другой расстановкой типов по вашему желанию.

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

let (statusCode, statusMessage) = http404Error
print("The status code is \(statusCode)")
// Выведет "The status code is 404"
print("The status message is \(statusMessage)")
// Выведет "The status message is Not Found"

Если вам нужны только некоторые из значений кортежа, вы можете игнорировать части кортежа во время разложения с помощью символа подчеркивания (_):

let (justTheStatusCode, _) = http404Error
print("The status code is \(justTheStatusCode)")
// Выведет "The status code is 404"

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

print("The status code is \(http404Error.0)")
// Выведет "The status code is 404"
print("The status message is \(http404Error.1)")
// Выведет "The status message is Not Found"

Вы можете давать имена отдельным элементам кортежа во время объявления:

let http200Status = (statusCode: 200, description: "OK")

Когда вы присвоили имя элементу кортежа, вы можете обратиться к нему по имени:

print("The status code is \(http200Status.statusCode)")
// Выведет "The status code is 200"
print("The status message is \(http200Status.description)")
// Выведет "The status message is OK"

Кортежи особенно полезны в качестве возвращаемых значений функций. Функция, которая пытается получить веб-страницу, может вернуть кортеж типа (Int, String), чтобы описать успех или неудачу в поиске страницы. Возвращая кортеж с двумя отдельными значениями разного типа, функция дает более полезную информацию о ее результате, чем, если бы, возвращала единственное значение одного типа, возвращаемое функцией. Для более подробной информации смотрите главу Функции, возвращающие несколько значений.

Заметка

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

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

Заметка

В C или Objective-C нет понятия опционалов. Ближайшее понятие в Objective-C это возможность вернуть nil из метода, который в противном случае вернул бы объект. В этом случае nil обозначает «отсутствие допустимого объекта». Тем не менее, это работает только для объектов, и не работает для структур, простых типов C, или значений перечисления. Для этих типов, методы Objective-C, как правило, возвращают специальное значение (например, NSNotFound), чтобы указать отсутствие значения. Этот подход предполагает, что разработчик, который вызвал метод, знает, что есть это специальное значение и что его нужно учитывать. Опционалы Swift позволяют указать отсутствие значения для абсолютно любого типа, без необходимости использования специальных констант.

Приведем пример, который покажет, как опционалы могут справиться с отсутствием значения. У типа Int в Swift есть инициализатор, который пытается преобразовать значение String в значение типа Int. Тем не менее, не каждая строка может быть преобразована в целое число. Строка «123» может быть преобразована в числовое значение 123, но строка «hello, world» не имеет очевидного числового значения для преобразования.

В приведенном ниже примере используется метод Int() для попытки преобразовать String в Int:

let possibleNumber = "123"
let convertedNumber = Int(possibleNumber)
// для convertedNumber выведен тип "Int?", или "опциональный Int"

Поскольку метод Int() может иметь недопустимый аргумент, он возвращает опциональный Int, вместо Int. Опциональный Int записывается как Int?, а не Int. Знак вопроса означает, что содержащееся в ней значение является опциональным, что означает, что он может содержать некое Int значение, или он может вообще не содержать никакого значения. (Он не может содержать ничего другого, например, Bool значение или значение String. Он либо Int, либо вообще ничто)

nil

Мы можем установить опциональную переменную в состояние отсутствия значения, путем присвоения ему специального значения nil

var serverResponseCode: Int? = 404
// serverResponseCode содержит реальное Int значение 404
serverResponseCode = nil
// serverResponseCode теперь не содержит значения
Заметка

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

Если объявить опциональную переменную без присвоения значения по умолчанию, то переменная автоматически установится в nil для вас:

var surveyAnswer: String?
// surveyAnswer автоматически установится в nil
Заметка

nil в Swift не то же самое что nil в Objective-C. В Objective-C nil является указателем на несуществующий объект. В Swift nil не является указателем, а является отсутствием значения определенного типа. Устанавливаться в nil могут опционалы любого типа, а не только типы объектов.

Инструкция If и Принудительное извлечение

Вы можете использовать инструкцию if, сравнивая опционал с nil, чтобы проверить, содержит ли опционал значение. Это сравнение можно сделать с помощью оператора «равенства» (==) или оператора «неравенства» (!=).

Если опционал имеет значение, он будет рассматриваться как «неравным» nil:

if convertedNumber != nil {
    print("convertedNumber contains some integer value.")
}
// Выведет "convertedNumber contains some integer value."

Если вы уверены, что опционал содержит значение, вы можете получить доступ к его значению, добавив восклицательный знак (!) в конце имени опционала. Восклицательный знак фактически говорит: «Я знаю точно, что этот опционал содержит значение, пожалуйста, используй его». Это выражение известно как Принудительное извлечение значения опционала:

if convertedNumber != nil {
    print("convertedNumber has an integer value of \(convertedNumber!).")
}
// Выведет "convertedNumber has an integer value of 123."

Более подробную информацию об инструкции if можно получить в главе Управление потоком.

Заметка

Попытка использовать ! к несуществующему опциональному значению вызовет runtime ошибку. Всегда будьте уверены в том, что опционал содержит не-nil значение, перед тем как использовать ! чтобы принудительно извлечь это значение.

Привязка опционалов

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

Привязку опционалов для инструкции if можно писать как показано ниже:

  1. if let constantName = someOptional {
  2.     statements
  3. }

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

if let actualNumber = Int(possibleNumber) {
    print("\(possibleNumber) has an integer value of \(actualNumber)")
} else {
    print("\(possibleNumber) could not be converted to an integer")
}
// Выведет "123" has an integer value of 123

Это может быть прочитано как:

«Если опциональный Int возвращаемый Int(possibleNumber) содержит значение, установи в новую константу с названием actualNumber значение, содержащееся в опционале.»

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

Вы можете использовать и константы и переменные для привязки опционалов. Если вы хотели использовать значение actualNumber внутри первого ветвления инструкции if, вы могли бы написать if var actualNumber вместо этого, и значение, содержащееся в опционале, будет использоваться как переменная, а не константа.

Вы можете включать столько опциональных привязок и логических условий в единственную инструкцию if, сколько вам требуется, разделяя их запятыми. Если какое-то значение в опциональной привязке равно nil, или любое логическое условие вычисляется как false, то все условия выражения будет считаться false. Следующие инструкции if эквиваленты:

if let firstNumber = Int("4"), let secondNumber = Int("42"), firstNumber < secondNumber && secondNumber < 100 {
    print("\(firstNumber) < \(secondNumber) < 100")
}
// Выведет "4 < 42 < 100"
 
if let firstNumber = Int("4") {
    if let secondNumber = Int("42") {
        if firstNumber < secondNumber && secondNumber < 100 {
            print("\(firstNumber) < \(secondNumber) < 100")
        }
    }
}
// Выведет "4 < 42 < 100"
Заметка

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

Неявно извлеченные опционалы

Как описано выше, опционалы показывают, что константам или переменным разрешено не иметь «никакого значения». Опционалы можно проверить с помощью инструкции if, чтобы увидеть существует ли значение, и при условии, если оно существует, можно извлечь его с помощью привязки опционалов для доступа к опциональному значению.

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

Эти виды опционалов называются неявно извлеченные опционалы. Их можно писать, используя восклицательный знак (String!), вместо вопросительного знака (String?), после типа, который вы хотите сделать опциональным.

Неявно извлеченные опционалы полезны, когда известно, что значение опционала существует непосредственно после первого объявления опционала, и точно будет существовать после этого. Неявно извлечённые опционалы в основном используются во время инициализации класса, как описано в разделе «Бесхозные ссылки и неявно извлеченные опциональные свойства».

Честно говоря, неявно извлеченные опционалы — это нормальные опционалы, но они могут быть использованы как не опциональные значения, без необходимости в извлечении опционального значения каждый раз при доступе. Следующий пример показывает разницу в поведении между опциональной строкой и неявно извлеченной опциональной строкой при доступе к их внутреннему значению как к явному String:

let possibleString: String? = "An optional string."
let forcedString: String = possibleString! // необходим восклицательный знак

let assumedString: String! = "An implicitly unwrapped optional string."
let implicitString: String = assumedString // восклицательный знак не нужен

Вы можете считать неявно извлеченные опционалы обычными опционалами дающими разрешение на принудительное извлечение, если это требуется. Когда вы используете неявно извлеченный опционал, то Swift сначала пробует использовать его в качестве обычного опционального значения, если так его использовать не получается, то уже пробует принудительно извлечь значение. В коде выше опциональное значение assumedString является принудительно извлеченным прежде, чем будет записано в implicitString, так как implicitString имеет явный неопциональный тип String. В коде ниже optionalString не имеет явного типа, так что является обычным опционалом.

let optionalString = assumedString
// Тип optionalString является "String?" и assumedString не является принудительно извлеченным значением.

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

Вы можете проверить не является ли неявно извлеченный опционал nil точно так же как вы проверяете обычный опционал:

if assumedString != nil {
    print(assumedString!)
}
// Выведет "An implicitly unwrapped optional string."

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

if let definiteString = assumedString {
  print(definiteString)
}
// Выведет "An implicitly unwrapped optional string."
Заметка

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

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

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

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

func canThrowAnError() throws {
// эта функция может сгенерировать ошибку
}

Функция сообщает о возможности генерации ошибки, включив ключевое слово throws в объявление. Когда вы вызываете функцию, которая может выбросить ошибку, вы добавляете ключевое слово try в выражение. Swift автоматически передает ошибки из их текущей области, пока они не будут обработаны условием catch.

do {
  try canThrowAnError()
  // ошибка не была сгенерирована
} catch {
  // ошибка сгенерирована
}

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

Вот пример того, как обработка ошибок может быть использована в ответ на различные условия возникновения ошибок:

func makeASandwich() throws {
    // ...
}
 
do {
    try makeASandwich()
    eatASandwich()
} catch SandwichError.outOfCleanDishes {
    washDishes()
} catch SandwichError.missingIngredients(let ingredients) {
    buyGroceries(ingredients)
}

В этом примере, функция makeASandwich() генерирует ошибку, если нет чистых тарелок или если отсутствуют какие-либо ингредиенты. Так как makeASandwich() может выдавать ошибку, то вызов функции заворачивают в выражении try. При заворачивании вызова функции в выражение do, генерация каких-либо ошибок, будет передаваться на предусмотренные условия catch.

Если ошибка не генерируется, то вызывается функция eatASandwich(). Если ошибка все таки генерируется, и она соответствует SandwichError.outOfCleanDishes, то вызывается функция washDishes(). Если генерируется ошибка, и она соответствует SandwichError.missingIngredients , то функция buyGroceries(_:) вызывается с соответствующим значением [String], захваченным шаблоном catch.

Генерация, вылавливание и передача ошибок рассмотрены более подробно в главе Обработка ошибок.

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

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

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

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

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

Отладка с помощью утверждений

Утверждения записываются как функция стандартной библиотеки Swift assert(_:_:file:line:). Вы передаете в эту функцию выражение, которые оценивается как true или false и сообщение, которое должно отображаться, если результат условия будет false. Например:

let age = -3
assert(age >= 0, "Возраст человека не может быть меньше нуля")
// это приведет к вызову утверждения, потому что age >= 0, а указанное значение < 0.

В этом примере, выполнение кода продолжится, только если age >= 0 вычислится в true, что может случиться, если значение age не отрицательное. Если значение age отрицательное, как в коде выше, тогда age >= 0 вычислится как false, и запустится утверждение, завершив за собой приложение.

Сообщение утверждения можно пропускать по желанию, как в следующем примере:

assert(age >= 0)

Если код уже проверяет условие, то вы используете функцию assertionFailure(_:file:line:) для индикации того, что утверждение не выполнилось. Например:

if age > 10 {
    print("Ты можешь покататься на американских горках и чертовом колесе.")
} else if age > 0 {
    print("Ты можешь покататься на чертовом колесе.")
} else {
    assertionFailure("Возраст человека не может быть отрицательным.")
}

Обеспечение предусловиями

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

Для использования предусловий вызовите функцию precondition(_:_:file:line:). Вы передаете этой функции выражение, которое вычисляется как true или false и сообщение, которое должно отобразиться, если условие будет иметь значение как false. Например:

 // В реализации сабскрипта...
precondition(index > 0, "Индекс должен быть больше нуля.")

Вы так же можете вызвать функцию preconditionFailure(_:_:file:line:) для индикации, что отказ работы уже произошел, например, если сработал дефолтный кейс инструкции switch, когда известно, что все валидные значения должны быть обработаны любым кейсом, кроме дефолтного.

Заметка

Если вы компилируете в режиме -0unchecked, то предусловия не проверяются. Компилятор предполагает, что предусловия всегда получают значения true, и он оптимизирует ваш код соответствующим образом. Однако, функция fatalError(_:file:line:) всегда останавливает исполнение, несмотря на настройки оптимизации.

Вы можете использовать функцию fatalError (_:file:line:) во время прототипирования или ранней разработки для создания заглушек для функциональности, которая еще не реализована, написав fatalError («Unimplemented») в качестве реализации заглушки. Поскольку фатальные ошибки никогда не оптимизируются, в отличие от утверждений или предусловий, вы можете быть уверены, что выполнение кода всегда прекратится, если оно встречает реализацию заглушки.

Если вы нашли ошибку, пожалуйста, выделите фрагмент текста и нажмите Ctrl+Enter.

React Native vs Swift: Что Лучше Подходит Для Разработки MVP?

Однажды стартапер поспорил, что сможет написать самый короткий рассказ, способный растрогать любого. Он выиграл спор: «Продается приложение для iOS. Написано на Swift». Мы в Purrweb не любим грустить, поэтому используем React Native. Кроссплатформенный фреймворк позволяет быстро написать код, подходящий для iOS и Android. В этой статье рассмотрим другие преимущества React Native и сравним его со Swift — нативным языком от компании Apple. Добро пожаловать на поединок React Native vs Swift!

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

Нативная разработка  

Нативные приложения разрабатывают только под одну операционную систему. Такое приложение создано с использованием языков программирования для приложений и инструментов, специфичных для одной платформы. Например, можно разработать приложение для Android на Java или Kotlin, а для iOS выбрать Swift и Objective-C.

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

Кроссплатформенная разработка 

И все-таки: React Native vs Swift, что круче? Кроссплатформенная разработка — процесс создания приложения, которое работает на нескольких платформах. Это делается с помощью таких инструментов, как React Native, Xamarin и Flutter. Приложения, написанные с помощью этих технологий, можно развернуть как на Android, так и на iOS.

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

Мы в Purrweb специализируемся на создании MVP — минимально жизнеспособного продукта, приложения, сокращенного до основной функциональности без UI/UX изысков и сложной разработки. MVP нужен стартапу как воздух: он помогает представить идею инвесторам и получить деньги на дальнейшую разработку. Здесь как раз нужно быстро и без лишних вложений разработать «первую версию» приложения, так что кроссплатформенная разработка, языки программирования для приложений и MVP идут рука об руку. 

Android или iOS?

Когда речь идет о нативных приложениях, нужно выбрать, для какой операционной системы писать в первую очередь и какой язык программирования для приложений использовать. Вот и начинается борьба React Native vs Swift. Если кратко: для iOS. Пользователи этой операционной системы привыкли платить за контент и приложения. Ребята с айфонами  — еще и лидеры мнений, поэтому показать им MVP в первую очередь выгодно для стартапа.

Этот план звучит как «трата времени и денег» для стартапа 🤪

Если все-таки пришлось сначала писать приложение для iOS, советуем сделать это на React Native. Так вы сэкономите не только время на поиск и онбординг новой команды, но и на разработке второго приложения. На выходе получите кроссплатформенное MVP, которое легко переобувается в обе платформы. Круто? Конечно!

Почему React Native?   

В битве React Native vs Swift для стартапа побеждает React Native. И не потому что мы используем этот язык в своих проектах — тут все честно! Вот несколько преимуществ, которые стартапер оценит уже на ранних стадиях разработки проекта. 

Экономия денег и времени

Вы спрашиваете: React Native vs Swift, а мы не устаем повторять, как хорошо React Native справляется с задачей «сэкономить как можно больше ресурсов». Время, деньги и силы стартапера, которые уходят на поиск, онбординг и работу с нативными командами. А потом эти команды — хорошо, если параллельно — берутся за разработку, делают приложение, приносят его на правки тестируют, правят, тестируют, правят… Ну, вы поняли. 

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

Еще немного про экономию 

Кроме того, нативные разработчики iOS обычно имеют высокие зарплаты, в то время как разработчики кроссплатформенных мобильных устройств будут брать с вас меньше. Например, Android-разработчику придется заплатить $1500, а разработчику на React Native — в три раза меньше. Stonks! 

Переиспользование кода

Код, написанный на React Native, легко «переобуть» под любой платформу, будь то iOS или Android. Переиспользовать код гораздо проще, чем написать новый, и это опять же экономит время и деньги стартапера. Забавный факт: код, написанный на React Native для iOS, не будет сильно отличаться от нативного.

Низкий порог входа в технологию

Наши разработчики говорят, что освоить язык JavaScript и фреймворк React Native проще, чем Swift. Если команда уже пишет веб-приложения на React, то обучиться созданию кроссплатформенных приложений для мобильных устройств не составит труда. 

Многие фронтендеры знают технологии HTML, CSS, JavaScript и React. А React Native — это JS-фреймворк. И пусть RN не использует HTML для рендеринга приложения, но предоставляет схожий с HTML набор компонентов. Для стилизации компонентов React Native использует JS-таблицы стилей, которые также похожи на обычные таблицы CSS.

Глеб Комаров, 
фронтенд разработчик в Purrweb

Возможность добавлять нативные элементы

Яркий пример приложения с нативными элементами — Instagram. Несмотря на то, что приложение написано на React Native, внутри есть много нативных элементов. Дело в том, что в React Native легко интегрируются части нативного кода, и это улучшает качество работы приложения. 

На проекте EnerGO прилетела хотелка от заказчика: реализовать привязку кредитной карты с помощью Google Pay и Apple Pay и проводить платежи через платежную систему CloudPayments. У React Native большое коммьюнити разработчиков, но готовых либ (библиотек) и сдэкашек (наборов средств разработки) на него нет. Мы решили, что сами напишем либу под React Native. К счастью, архитектура фреймворка позволяет использовать нативный код в любом проекте.

Антон Вотинов, 
фронтенд разработчик в Purrweb

Приложения на React Native от Purrweb

В Purrweb мы делаем классные MVP на React Native. React Native vs Swift — тут даже думать не надо. В этой области у нас неплохая экспертиза, поэтому в этой статье сделали подборку именно наших приложений. Мы еще не написали свой Instagram, Skype или UberEats, но парочку интересных проектов все-таки реализовали (на самом деле их количество давно перевалило за сотню). Рассказываем про яркие примеры нашей работы с React Native. 

А тут найдете топ-20 приложений на React Native — обновленная версия 2021 года, залетайте за свежими идеями 🤗 

TuneTank 

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

Talentum  

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

EnerGO

Разработка мобильного приложения с железом из Китая похожа на первую поездку на велосипеде: колеса умеют ездить только по китайским дорогам, ты знаешь, как крутить педали, но не понимаешь, как связать с ними ноги. Такой “поездкой” для нас стала разработка IoT приложения EnerGO. EnerGO — стартап, с помощью которого пассажиры московского метро и посетители кафе могут арендовать павербанки для смартфонов на одной станции и оставлять на другой.

EyeBuy 

Когда мы делали EyeBuy, в России еще не было аналогов такому приложению. Спойлер: до сих пор нет. Live-stream-shopping индустрия движется к нам из Китая, но пока еще не обрела должной популярности. Покупать товары прямо на стриме — круто, не так ли? В EyeBuy мы реализовали возможность добавлять вещи в корзину, пока стрим еще не кончился —  чтобы ничего не потерять. Тестировали пилот приложения сразу с крупными брендами, а на стрим залетели 500 зрителей. 

Lytic 

Lytic — чудо-стартап, который пришел к нам с $1,5K, а ушел с $400K. Идея сервиса заключается в следующем: если человека что-то беспокоит, он может написать свои симптомы в приложении. Чат-бот задаст уточняющие вопросы и подскажет причины плохого самочувствия. После этого приложение порекомендует, какие анализы нужно сдать, и предложит записаться к врачу, который специализируется на данных заболеваниях. Интересно, скачали бы вы такое приложение? Мы бы да!

Парочка выводов

React Native vs Swift — для стартапа больше подходит RN

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

Много хороших примеров 

Instagram, Skype, Walmart, Tesla, Facebook, Wix — вот неполный список приложений, написанных на React Native. Помимо всем известных гигантов только в портфолио  Purrweb больше сотни успешных проектов с этим фреймворком. У нас целая команда — больше 50-ти! — специалистов, которые не первый год работают с технологией, и за три месяца сделают крутое MVP для вашего стартапа!

 

У вас есть идея для проекта?
X

В МИД России рассказали о необходимости быть готовыми к отключению от SWIFT

Глава департамента экономического сотрудничества МИД РФ Дмитрий Биричевский назвал западные санкции «барьером» для защиты своих производителей. При этом он не исключил, что в качестве одной из мер против России может быть использовано отключение от системы межбанковского обмена информацией SWIFT. В Москве ранее рассказывали, как готовятся к возможной реализации такого сценария.

Барьер Запада

Межбанковская система передачи информации SWIFT может быть вовлечена в «санкционную спираль» против России. Об этом директор департамента экономического сотрудничества МИД РФ Дмитрий Биричевский рассказал «РИА Новости».

По его словам, в последнее время «раздаются угрозы, прежде всего из Соединенных Штатов, отключить Россию от системы SWIFT». Однако Биричевский подчеркнул, что только Совбез ООН может вводить подобные меры.

Дипломат также отметил, что односторонние санкции, вводимые США и другими странами, — «это, скорее, барьеры в целях защиты собственных производителей и защиты собственных интересов на мировой арене».

Что такое SWIFT

Международная межбанковская система передачи информации и совершения платежей SWIFT была создана в 1973 году. Она позволяет банкам во всём мире отправлять и получать информацию о финансовых операциях в безопасной и стандартизированной форме.

К SWIFT подключены порядка 11 тыс. крупнейших финансовых и кредитных организаций в 220 странах. Ежедневно система обеспечивает прохождение не менее миллиона финансовых операций.

«Ядерная опция»

В начале мая госсекретарь США Энтони Блинкен ушел от ответа на вопрос о возможном отключении России от системы межбанковских платежей SWIFT.

«Я не хотел бы отвечать на гипотетические вопросы о том, что мы могли бы сделать в будущем. Позвольте мне просто сказать, что когда речь идет о сдерживании агрессии или ответе на нее, мы рассмотрим все разумные варианты», – ответил глава Госдепартамента.

При этом он подчеркнул, что США предпочли бы иметь с Россией «более стабильные предсказуемые отношения». 16 мая комитет по международным отношениям Европарламента представил проект документа, описывающего основные принципы выстраивания отношений с Россией. Среди всего прочего там рекомендовалось ЕС для «защиты демократии во всем мире» объединиться с США и разработать совместные меры санкционного давления.

В документе отмечалось, что Брюсселю следует быть готовым к отключению Москвы от международной платежной системы SWIFT, если РФ продолжит «агрессивные угрозы и военные действия». В конце апреля евродепутаты также призывали отключить Россию от SWIFT в случае «продолжения агрессии» на Украине.

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

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

«Готовиться обязательно надо»

Пресс-секретарь президента России Дмитрий Песков 22 марта тоже заявил, что исключать угрозу отключения РФ от системы межбанковских платежей SWIFT нельзя, потому что действия российских оппонентов непредсказуемы.

В то же время Высокий представитель ЕС по внешней политике и политике безопасности Жозеп Боррел, считает, что у Евросоюза нет компетенции для отключения, так как SWIFT — это международная частная организация.

Банк России 18 мая также отметил, что не видит рисков отключения страны от международной системы межбанковских платежей SWIFT. ЦБ поддерживает прямой контакт со штаб-квартирой и московским офисом SWIFT. Там заверяют, что система «будет работать штатно, без каких-либо проблем».

При этом, по словам зампреда ЦБ Ольги Скоробогатовой, даже в случае отключения от SWIFT РФ способна справиться с этим с помощью Системы передачи финансовых сообщений (СПФС).
«Весь внутрироссийский трафик, даже если что-то произойдет, может спокойно быть переведен на нашу систему», — подчеркнула Скоробогатова.

СПФС — это альтернативный канал передачи электронных сообщений по финансовым операциям, который, как отмечают в ЦБ РФ, гарантирует бесперебойность передачи финансовых сообщений как внутри страны, так и за ее пределами. На данный момент к ней подключены 23 зарубежных участника из Армении, Белоруссии, Казахстана, Киргизии, Германии и Швейцарии.

Директор департамента экономического сотрудничества МИД РФ Дмитрий Биричевский также отметил, что Москва готовит меры защиты на случай отключения.

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

В Совфеде оценили риск отключения России от SWIFT — РБК

Фото: Chris Helgren / Reuters

В ближайшее время России не грозит отключение от системы межбанковских платежей SWIFT, заявила РБК первый заместитель председателя комитета Совета Федерации по бюджету и финансовым рынкам Елена Перминова.

«В целом, если бы эта проблема была реальной, мы бы уже давно были к этому готовы. А насколько я знаю, Россия готовится к этому, но не форсирует это событие», — рассказала сенатор.

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

«Это очень сложно сделать. Платежная система SWIFT — международная. Не только Россия задействована в этой системе, но и множество стран. Россия является крупнейшим партнером многих из них. Поэтому если ее отключить от SWIFT, то пострадает не только Россия, но и другие страны. Я думаю, что такие предложения не имеют экономического обоснования и не совсем грамотные», — отметила Перминова.

В МИДе отвергли создание альтернативной системы SWIFT в скором времени

С точки зрения SWIFT. Что финансовым учреждениям стоит сделать для усиления киберзащиты в 2021 году

BIS Journal №2(41)/2021

22 июня, 2021

С точки зрения SWIFT. Что финансовым учреждениям стоит сделать для усиления киберзащиты в 2021 году

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

 

АТТЕСТАЦИЯ CSCF

К концу прошлого года 89% наших клиентов, которые представляют более 99% трафика SWIFT, прошли аттестацию на соблюдение обязательных элементов контроля, предусмотренных Концепцией обеспечения безопасности пользователей (CSCF). Данная концепция — ключевой элемент CSP.

Мы благодарим наше сообщество, а именно более 11 000 учреждений, за внедрение элементов контроля, предусмотренных концепцией CSCF в 2019 году. 89% аттестованных участников – прекрасное достижение, особенно в таком непростом контексте. В условиях пандемии COVID-19 многим учреждениям пришлось уделить основное внимание непрерывности бизнеса и в некоторых случаях даже заморозить другие процессы.

CSCF как основа киберзащиты сообщества SWIFT выделяет обязательные и рекомендательные элементы контроля, которые клиенты могут внедрить в локальной среде для предотвращения существующих и новых киберугроз. С момента своего запуска в 2017 году концепция стремится постоянно повышать планку безопасности для всего сообщества SWIFT.

 

И это работает

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

 

CSPВ МЕЖДУНАРОДНОМ КОНТЕКСТЕ

Как SWIFT объединяет усилия с другими крупным и инфраструктурами в Европе для борьбы с киберугрозой

SWIFT как участник рабочей группы Европейского совета по кибербезопасности для панъевропейских финансовых инфраструктур (ECRB), созданного Европейским центральным банком, был ключевым игроком в запуске инициативы, согласно которой крупные европейские инфраструктуры должны делиться значимой информацией о киберугрозе. Её цель – помочь защитить европейских граждан и финансовые учреждения от кибермошенников.

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

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

Чтобы решить эту проблему, Европейский совет по кибербезопасности для панъевропейских финансовых инфраструктур создал рабочую группу для обмена информацией. Основные цели программы, известной как Инициатива по обмену киберинформацией и аналитическими данными (CIISI-EU), следующие:

Предотвращать, обнаруживать, реагировать и повышать осведомлённость членов ECRB об угрозах в сфере кибербезопасности.

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

Поощрять активное участие членов «доверенного круга» вместо пассивного потребления или малоэффективного использования информации.

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

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

В ECRB входят крупнейшие и наиболее важные рыночные инфраструктуры ЕС. Это центральные банки, клиринговые палаты, фондовые биржи, поставщики платёжных услуг, правоохранительные органы и многие другие.

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

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

Впервые в истории крупные финансовые инфраструктуры, Европол и Агентство Европейского союза по кибербезопасности (ENISA) предпринимают совместные шаги по борьбе с киберугрозами. Мы надеемся, что это сотрудничество вдохновит другие юрисдикции на борьбу с одной из самых опасных угроз нашего времени. Обмен информацией — это перспективный способ предотвращения мошенничества и в конечном счёте защиты средств граждан.

 

СОВМЕСТНОЕ РАССЛЕДОВАНИЕ

Как преступники обналичивают средства, полученные в результате масштабных кибератак

В рамках реализации CSP в прошлом году SWIFT совместно с BAE Systems провёл расследование процесса отмывания денег. По его итогам был выпущен совместный отчёт «По следам денег» (Follow the Money), в котором описывается сложная схема преступников по использованию «денежных мулов», подставных компаний и криптовалют для обналичивания средств, полученных в результате кибератаки.

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

Методы, используемые преступниками при осуществлении кибератак, достаточно хорошо изучены, в отличие от того, что происходит с деньгами после кражи. Цель отчёта – осветить способы «обналичивания» украденных средств, используемые киберпреступниками, чтобы глобальное сообщество SWIFT, состоящее из более чем 11 000 финансовых организаций, рыночных инфраструктур и корпораций, могло лучше себя защитить.

 

Другие выводы отчёта

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

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

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

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

 

ПО РЕКОМЕНДАЦИИ SWIFT

Что клиентам стоит сделать в 2021 году для поддержания своей безопасности

Использование таких инструментов, как обязательные элементы контроля, обмен аналитическими данными и экспертиза, позволяет CSP непрерывно помогать финансовому сообществу укреплять свою безопасность. CSCF 2021 года включает ряд дополнительных требований, 22 обязательных и 9 рекомендательных элементов контроля, по которым каждому клиенту нужно пройти аттестацию. О них было объявлено в 2020 году со сроком исполнения в конце 2021 года.

Два элемента контроля, 1.3 и 2.10, заявленные как рекомендательные в 2019 году, в CSCF 2020 года уже переведены в разряд обязательных. В CSCF 2021 года обязательным стал прежде дополнительный элемент контроля 1.4. Эти дополнения призваны обеспечить защиту и уменьшить потенциальную уязвимость критических компонентов интерфейса, а также критических систем, в которых более часто используется виртуализация.

Аттестация по версии CSCF 2021 года в KYC-SA, онлайн-хранилище данных об аттестации клиентов, станет доступной с июля 2021 года.

Все элементы контроля CSP соответствуют высшим отраслевым стандартам, включая Стандарт безопасности данных индустрии платёжных карт (PCI DSS), рамочные требования Национального института стандартов и технологий (NIST) и модель ISO/IEC 27001. Следуя общим принципам, организации-участники CSP смогут повысить эффективность, снизить затраты и обеспечить надёжность своей инфраструктуры.

 

НОВОЕ В 2021 ГОДУ

Требуется независимая оценка

Для повышения целостности и надёжности информации об аттестациях пользователей все аттестации в соответствии с требованиями CSCF 2021 года должны быть подтверждены независимой оценкой.

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

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

Чтобы поддержать наших клиентов, мы создали директорию компаний, оказывающих услуги по проведению CSP-оценки. Список составлялся с учётом таких критериев, как опыт и квалификация служб кибербезопасности; стратегическая ориентация на услуги кибербезопасности; хорошая репутация и желание работать с клиентами из финансовой сферы. Ознакомиться с ним можно на swift.com. Обратите внимание, что клиенты также могут заключить договор с компаниями, не указанными в списке.

 

КРАЙНИЙ СРОК

Когда необходимо пройти аттестацию?

Крайний срок, когда необходимо подтвердить соответствие требованиям CSCF 2021 года и предоставить независимую оценку аттестации, — 31 декабря 2021 года.

 

ВЫСОКИЙ УРОВЕНЬ

Как прошла аттестация в 2020 году?

В результате усилий нашего сообщества по оценке своего соответствия требованиям CSCF мы увидели значительный уровень аттестации в 2020 году. Средний уровень соответствия по каждому обязательному элементу контроля варьировался от 93 до 99%.

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

Смотрите также

Отключение от мира: чем еще грозит России блокировка SWIFT

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

Зачем нас столько лет пугают отключением SWIFT? «Обратите внимание, что об отключении России от SWIFT все время говорят политики, а не банкиры, — говорит доцент факультета финансов и банковского дела РАНХиГС Сергей Хестанов. — Хотя теоретическая возможность подобного отключения и существует, воплощение этой угрозы в реальность лично мне представляется маловероятным. В том числе и потому, что на Западе достаточно сильны лоббистские настроения, направленные на то, чтобы этого не допустить. Но даже если это и произойдёт, то для внутрироссийских платежей абсолютно ничего не изменится, так как у нас существуют несколько аналогов SWIFT. Самый крупный и наиболее отработанный — система передачи финансовых сообщений Центрального банка РФ, кроме этого есть система Cyberplat, система Национального депозитарного центра и некоторые другие. С платежами за рубеж будет несколько сложнее, к счастью, имеется несколько немецких и швейцарских банков, подключённых к российскому аналогу. Я ещёезастал советские времена, тогда для этих целей использовались Совзагранбанки, они были открыты как иностранные юрлица, но принадлежали СССР. Их было много в разных странах, даже в США, но основной оборот велся через французские и бельгийские представительства. То есть сегодня достаточно иметь хотя бы один такой банк. Да, возможно, чуть-чуть медленнее будут проходить платежи, ну как медленнее — на несколько десятков секунд, это ведь раньше все считали вручную. До тех пор пока под санкции не попадают банки-посредники, проблем вообще нет. Собственно весь советский период так торговля и шла, до 1989 года и появление у нас SWIFT. Для малых компаний и мелких платежей неудобства могут быть только в переходный период, думаю, месяца три.

— А по простым обывателям ударит?

— Возможно, в первое время возникнут сложности с банковскими картами. Система «Мир», мягко говоря, в Европе не распространена. Но люди знающие в курсе, что существует совместная с Китаем банковская карта с двумя чипами. Крупные иностранные банки эту карту принимают почти все. Хотя в европейской глубинке, может быть, ещё стоят банкоматы старого образца, которым она не знакома. Для этих целей надо иметь по старинке кошелёчек с наличкой, вешать его на грудь, чтобы не потерять и чтобы не украли. И у меня такой тоже был когда-то. Кстати, надо его поискать…

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

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

Тема возможного отключения России от международной межбанковской системы передачи информации и совершения платежей SWIFT встаёт на повестке дня периодически с 2014 года, начиная с войны на Донбассе. В Кремле такую возможность не исключают, об этом регулярно говорит пресс-секретарь президента России Дмитрий Песков. Надо заметить, штаб-квартира SWIFT находится в Бельгии, недалеко от Брюсселя. SWIFT является кооперативным обществом, созданным по бельгийскому законодательству, принадлежит его членам. То есть это не американская организация, хотя диктовать свои условия всем остальным пытаются именно они.

Вообще же к SWIFT подключены более 11 тысяч крупнейших организаций примерно в 200 странах. И понятно, что отключение России не в интересах этой организации. Поэтому все понимают, что это вопрос не экономический, а политический. Смогут ли политики протолкнуть свои интересы? Нет дыма без огня и общая нервозность явно просматривается в последних новостях об отключении SWIFT.

Кандидат юридических наук в области международного права Марина Силкина полагает, что резолюция Европарламента о возможном отключении России от SWIFT носит рекомендательный характер. «Чтобы такое решение стало обязательным, необходимо утверждение советом Евросоюза. При реализации таких мер проиграют обе стороны. В России, безусловно это удар по банковской системе, скорее всего все банки не отключат, а только часть «ведущих», которые будут вынуждены самостоятельно искать взаимодействие с платёжными системам других банков для зарубежных расчетов, в том числе через страны ЕАЭС. Прекратить закупку нефти и газа у Москвы это вообще на мой взгляд трудно реализуемое условие для Евросоюза, что они будут делать при возникновении энергетического коллапса, перейдут на сланцевый газ США? Есть внешний долг России, международные институты , организации с иностранными инвесторами, которые нужно обслуживать и принятие таких непопулярных мер может повлечь для них серьезные убытки», — говорит эксперт.

Swift — разработчик Apple

Современное

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

  struct Player {
    имя переменной: Строка
    var highScore: Int = 0
    var history: [Int] = []

    init (_ имя: String) {
        self.name = имя
    }
}

var player = Player ("Томас")  

Объявите новые типы с помощью современного простого синтаксиса. Задайте значения по умолчанию для свойств экземпляра и определите настраиваемые инициализаторы.

  extension Player {
    мутирующая функция updateScore (_ newScore: Int) {
        history.append (newScore)
        если highScore  

Добавьте функциональность к существующим типам с помощью расширений и сократите количество шаблонов с помощью настраиваемых строковых интерполяций.

  extension Player: Codable, Equatable {}

импортный фундамент
пусть кодировщик = JSONEncoder ()
попробуйте кодировщик.кодировать (игрок)

печать (игрок)
  

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

  let player = getPlayers ()


let ranked = Players.sorted (по: {player1, player2 в
    player1.highScore> player2.highScore
})


let rankedNames = ranked.map {$ 0.name}
  

Выполняйте мощные пользовательские преобразования с помощью упрощенных замыканий.

Эти дальновидные концепции привели к созданию веселого и простого в использовании языка.

У

Swift есть много других функций, чтобы сделать ваш код более выразительным:

  • Мощные и простые в использовании универсальные шаблоны
  • Расширения протокола, упрощающие написание универсального кода
  • Функции первого класса и упрощенный синтаксис закрытия
  • Быстрая и лаконичная итерация по диапазону или коллекции
  • Кортежи и несколько возвращаемых значений
  • Структуры, поддерживающие методы, расширения и протоколы
  • Перечисления могут иметь полезные данные и поддерживать сопоставление с образцом
  • Шаблоны функционального программирования, e.г., карта и фильтр
  • Собственная обработка ошибок с помощью try / catch / throw

Разработано с учетом требований безопасности

Swift устраняет целые классы небезопасного кода. Переменные всегда инициализируются перед использованием, массивы и целые числа проверяются на переполнение, память управляется автоматически, а принудительный монопольный доступ к памяти защищает от многих ошибок программирования. Синтаксис настроен так, чтобы упростить определение вашего намерения - например, простые трехсимвольные ключевые слова определяют переменную (var) или константу (let).Swift активно использует типы значений, особенно для таких часто используемых типов, как массивы и словари. Это означает, что когда вы делаете копию чего-либо с этим типом, вы знаете, что это не будет изменено где-либо еще.

Еще одна функция безопасности заключается в том, что по умолчанию объекты Swift никогда не могут быть нулевыми. Фактически, компилятор Swift не даст вам попытаться создать или использовать объект nil с ошибкой времени компиляции. Это делает написание кода намного чище и безопаснее, а также предотвращает огромную категорию сбоев во время выполнения в ваших приложениях.Однако бывают случаи, когда значение nil является допустимым и подходящим. Для таких ситуаций в Swift есть инновационная функция, известная как optionals. Необязательный параметр может содержать nil, но синтаксис Swift заставляет вас безопасно работать с ним, используя? синтаксис, чтобы указать компилятору, что вы понимаете поведение и будете обрабатывать его безопасно.

  extension Collection, где Element == Player {
    
    func highScoringPlayer () -> Игрок? {
        return self.max (by: {$ 0.highScore <$ 1.highScore})
    }
}  

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

  if let bestPlayer = Players.highestScoringPlayer () {
    recordHolder = "" "
        Рекордсмен - \ (bestPlayer.name), \
        с высоким баллом \ (bestPlayer.highScore)!
        "" "
} еще {
    recordHolder = "В игры еще не играли.")
}
печать (recordHolder)


let highScore = player.highestScoringPlayer () ?. highScore ?? 0
  

Такие функции, как дополнительное связывание, необязательное связывание и объединение с нулевым значением, позволяют безопасно и эффективно работать с необязательными значениями.

Быстрый и мощный

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

Swift является преемником языков C и Objective-C.Он включает примитивы низкого уровня, такие как типы, управление потоком и операторы. Он также предоставляет объектно-ориентированные функции, такие как классы, протоколы и универсальные шаблоны, предоставляя разработчикам Cocoa и Cocoa Touch требуемую производительность и мощность.

Отличный первый язык

Swift может открыть двери в мир программирования. Фактически, он был разработан, чтобы стать первым языком программирования, независимо от того, учитесь ли вы в школе или исследуете новые пути карьерного роста. Для преподавателей Apple создала бесплатную программу обучения Swift как в классе, так и вне его.Начинающие программисты могут загрузить Swift Playgrounds - приложение для iPad, которое делает начало работы с кодом Swift интерактивным и увлекательным.

Начинающие разработчики приложений могут получить доступ к бесплатным курсам, чтобы научиться создавать свои первые приложения в Xcode. А магазины Apple Store по всему миру проводят сеансы Today at Apple Coding & Apps, на которых вы можете получить практический опыт работы с кодом Swift.

Узнайте больше об образовательных ресурсах Swift от Apple

Исходная и двоичная совместимость

В Swift 5 вам не нужно изменять какой-либо код Swift 4, чтобы использовать новую версию компилятора.Вместо этого вы можете начать использовать новый компилятор и выполнять миграцию в своем собственном темпе, используя преимущества новых функций Swift 5, по одному модулю за раз. А Swift 5 теперь представляет двоичную совместимость для приложений. Это означает, что вам больше не нужно включать библиотеки Swift в приложения, предназначенные для текущих и будущих выпусков ОС, потому что библиотеки Swift будут включены в каждый выпуск ОС в будущем. Ваши приложения будут использовать последнюю версию библиотеки в ОС, и ваш код будет продолжать работать без перекомпиляции.Это не только упрощает разработку вашего приложения, но также уменьшает размер вашего приложения и время его запуска.

Открытый исходный код

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

Кроссплатформенный

Swift уже поддерживает все платформы Apple и Linux, и члены сообщества активно работают над переносом на еще большее количество платформ. Сообщество SourceKit-LSP также работает над интеграцией поддержки Swift в широкий спектр инструментов разработчика. Мы рады видеть больше способов, с помощью которых Swift делает программное обеспечение более безопасным и быстрым, а также делает программирование более увлекательным.

Swift для сервера

Хотя Swift поддерживает множество новых приложений на платформах Apple, он также используется для нового класса современных серверных приложений.Swift идеально подходит для использования в серверных приложениях, которым требуется безопасность во время выполнения, производительность компиляции и небольшой объем памяти. Чтобы направить Swift в сторону разработки и развертывания серверных приложений, сообщество сформировало рабочую группу Swift Server. Первым продуктом этой работы стал SwiftNIO, кроссплатформенная платформа асинхронных событийно-управляемых сетевых приложений для высокопроизводительных протокольных серверов и клиентов. Он служит основой для создания дополнительных ориентированных на сервер инструментов и технологий, включая ведение журналов, метрики и драйверы баз данных, которые все находятся в активной разработке.

Чтобы узнать больше о сообществе Swift с открытым исходным кодом и рабочей группе Swift Server, посетите Swift.org

Детские площадки и цикл чтения-оценки-печати (REPL)

Как и Swift Playgrounds для iPad, игровые площадки в Xcode делают написание кода Swift невероятно простым и увлекательным. Введите строку кода, и результат появится немедленно. Затем вы можете быстро просмотреть результат со стороны вашего кода или закрепить результат прямо ниже. В представлении результатов могут отображаться графики, списки результатов или графики значений с течением времени.Вы можете открыть помощник по временной шкале, чтобы наблюдать за развитием и анимацией сложного представления, что отлично подходит для экспериментов с новым кодом пользовательского интерфейса или для воспроизведения анимированной сцены SpriteKit по мере ее написания. Когда вы усовершенствовали свой код на игровой площадке, просто переместите этот код в свой проект. Swift также является интерактивным, когда вы используете его в Терминале или в консоли отладки LLDB Xcode. Используйте синтаксис Swift для оценки и взаимодействия с вашим запущенным приложением или напишите новый код, чтобы увидеть, как он работает в среде, подобной сценарию.

Менеджер пакетов

Swift Package Manager - это единый кроссплатформенный инструмент для создания, запуска, тестирования и упаковки ваших библиотек и исполняемых файлов Swift.Пакеты Swift - лучший способ распространять библиотеки и исходный код среди сообщества Swift. Конфигурация пакетов написана на самом Swift, что упрощает настройку целей, объявление продуктов и управление зависимостями пакетов. Впервые в Swift 5 команда быстрого запуска теперь включает возможность импорта библиотек в REPL без необходимости создания исполняемого файла. Сам Swift Package Manager фактически построен на Swift и включен в проект с открытым исходным кодом Swift в виде пакета.

Взаимодействие с Objective-C

Вы можете создать совершенно новое приложение с помощью Swift сегодня или начать использовать код Swift для реализации новых функций и возможностей в своем приложении.Код Swift сосуществует вместе с вашими существующими файлами Objective-C в одном проекте с полным доступом к API Objective-C, что упрощает его внедрение.

Что есть в Swift

Время от времени я выделяю немного времени в своей повседневной жизни, чтобы изучить что-то о языке Swift, которого я еще не знаю. Еще многое предстоит изучить. Я документирую свои выводы в серии, которую я назвал What The Swift. Если вам интересно узнать о более тонких деталях языка Swift, то эта серия статей для вас.

В предыдущем эпизоде ​​этой серии мы обнаружили, что AnyObject - это протокол, определенный в стандартной библиотеке Swift. В сегодняшнем выпуске «What The Swift» я хочу показать вам, что такое Any . Чтобы узнать значение Any , нам нужно вернуться к стандартной библиотеке Swift.

Приготовьтесь играть

Откройте Xcode и создайте новую площадку. Выберите шаблон Blank из раздела iOS .

Назовите игровую площадку What The Swift , сообщите Xcode, где вы хотите сохранить игровую площадку, и нажмите Create .

Возвращение к стандартной библиотеке Swift

Очистите содержимое игровой площадки и объявите переменную myObject типа Any .

  var myObject: Любой
  

На этот раз Xcode не дает нам подсказки относительно значения Any .Ранее на этой неделе мы узнали, что AnyObject - это протокол. То же самое не похоже на Any . Меню автозаполнения Xcode показывает, что AnyObject - это протокол.

В документации неясно значение Any . Похоже, нам нужно копнуть немного глубже.

Нажмите Command и щелкните Any на игровой площадке, чтобы перейти к определению Any .Это нормально работало для AnyObject , но, похоже, не работает для Any . Означает ли это, что Any не определен в стандартной библиотеке Swift?

Язык программирования Swift

Давайте взглянем на язык программирования Swift, чтобы узнать больше о Any . В главе под названием Type Casting мы находим следующее.

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

Это начало. Это говорит нам о том, что значение Any шире, чем значение AnyObject . Любой может представлять что угодно, отсюда и название. Это также объясняет, почему Any не является протоколом. Несмотря на то, что мы знаем, что такое Any , я хотел бы узнать о нем больше. Это цель этой серии.

Любой и id

Поиск в Google приводит нас к статье в блоге Apple Swift. Название, Objective-C id as Swift Any , очень показательно.В статье обсуждается значение Any и AnyObject . Что еще более важно, он объясняет, что значение AnyObject и Any изменилось с выпуском Swift 3.

В Swift 3 тип id в Objective-C теперь сопоставляется с типом Any в Swift, который описывает значение любого типа, будь то класс, перечисление, структура или любой другой тип Swift.

Это изменение улучшает совместимость Swift и Objective-C.Коллекции Objective-C, например, могут содержать элементы любого типа начиная с Swift 3. Это означает, что тип Foundation NSArray может хранить экземпляры String , Float и Int .

Но я хочу узнать больше о том, почему и как. В статье упоминаются три предложения Swift Evolution: SE-0072, SE-0116 и SE-0131. Наиболее перспективным выглядит SE-0116.

SE-0116

SE-0116 подробно описывает, почему и как это изменение.Суть проста и понятна. Чтобы улучшить совместимость Objective-C и Swift, тип Objective-C id сопоставляется с типом Swift Any .

В Swift 2 id сопоставлен с AnyObject . Хотя это работало нормально, это было далеко от идеала. Мало того, что это иногда приводило к неожиданному поведению, решение не отражало одну из фундаментальных концепций Swift, типов значений . Objective-C и Swift сильно отличаются, если внимательно присмотреться к обоим языкам.

Изменение, внесенное SE-0116, означает, что должна быть возможность связать любой тип Swift с объектом Objective-C. Это не проблема для классов и мостовых типов значений, таких как Int , String и типов коллекций, определенных стандартной библиотекой Swift. Но есть множество типов значений, у которых нет аналога в Objective-C. Эти типы значений соединяются как непрозрачные объекты, экземпляры неизменяемого класса. Они непрозрачны, потому что имя и поведение этих классов не раскрываются.

Что такое AnyHashable

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

Начиная с Swift 3, стандартная библиотека Swift определяет супертип AnyHashable . Это означает, что типы, соответствующие протоколу Hashable , могут использоваться как AnyHashable . В стандартной библиотеке Swift AnyHashable определен как структура.

  публичная структура AnyHashable {

    public init  (_ base: H), где H: Hashable

    общедоступная база переменных: любое {get}

}
  

Супертип AnyHashable используется для переноса нетипизированных наборов и словарей из Objective-C в Swift.Например, свойство userInfo типа Notification Foundation имеет тип [AnyHashable: Any] .

  public struct Notification: ReferenceConvertible, Equatable, Hashable {

    ...

    /// Хранилище для значений или объектов, связанных с этим уведомлением.
    общедоступный var userInfo: [AnyHashable: Any]?

    ...

}
  

Какой Swift

Как только вы поймете значение Any и AnyHashable , большая часть тайны исчезнет.Я надеюсь, что этот эпизод также показал вам ценность проекта Swift Evolution . Многие предложения Swift Evolution представлены членами сообщества Swift, что приводит к созданию лучшего и надежного языка.

Что нового в Swift 5.4? - Взлом с помощью Swift

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

Улучшенный синтаксис неявных членов

SE-0287 улучшает способность Swift использовать неявные выражения членов, поэтому вместо поддержки только одного статического члена вы можете создавать из них цепочки.

Swift всегда имел возможность использовать неявный синтаксис членов для простых выражений, например, если вы хотите раскрасить текст в SwiftUI, вы можете использовать .red вместо Color.red :

  struct ContentView1: View {
    var body: some View {
        Текст («Ты не мой руководитель!»)
            .foregroundColor (.red)
    }
}  

До Swift 5.4 это не работало с более сложными выражениями. Например, если вы хотите, чтобы ваш красный цвет был слегка прозрачным, вам нужно написать это:

  struct ContentView2: View {
    var body: some View {
        Текст («Ты не мой руководитель!»)
            .foregroundColor (Color.red.opacity (0,5))
    }
}  

Начиная с Swift 5.4 компилятор может понимать несколько связанных членов, что означает, что можно вывести тип Color :

  struct ContentView3: View {
    var body: some View {
        Текст («Ты не мой руководитель!»)
            .foregroundColor (.red.opacity (0.5))
    }
}  

Несколько вариативных параметров в функциях

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

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

  func summarizeGoals (times: Int ..., Players: String ...) {
    let connectedNames = ListFormatter.localizedString (byJoining: игроки)
    пусть присоединилисьTimes = ListFormatter.localizedString (byJoining: times.map (String.init))

    print ("\ (times.count) голов, забитых \ (connectedNames) в следующие минуты: \ (connectedTimes)")
}  

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

  summarizeGoals (раз: 18, 33, 55, 90, игроки: «Дэни», «Джейми», «Рой»)  

Создание переменных, вызывающих одноименную функцию

от Swift 5.4 и далее можно создать локальную переменную, вызвав функцию с тем же именем. Это может показаться неясным, но на самом деле это проблема, с которой мы сталкиваемся постоянно.

Например, это создает структуру с методом цвета (forRow :) , который вызывается и назначается локальной переменной с именем color :

  struct Table {
    пусть count = 10

    цвет функции (для строки строки: Int) -> String {
        if row.isMultiple (of: 2) {
            вернуть "красный"
        } еще {
            вернуть "черный"
        }
    }

    func printRows () {
        для я в 0..  

Такое использование разрешено только в Swift 5.4 и новее. В более ранних версиях Swift он создавал круговую ссылку, потому что Swift не мог различить локальную константу color и вызываемый им метод цвета (forRow :) - вы бы увидели ошибку «Переменная, используемая в ее собственная начальная стоимость ».

Обычно это приводило к тому, что мы использовали либо self.color (forRow: 1989), , чтобы прояснить, что мы имеем в виду вызов метода, либо просто присвоили локальному значению какое-нибудь другое имя, например colorForRow .

К счастью, Swift 5.4 решает эту проблему и позволяет нам использовать более естественное именование.

Это изменение также позволяет нам делать локальные копии свойств и глобальных переменных. Например, мы можем взять копию свойства username , которое также называется username , например:

  struct User {
    let username = "Тейлор"

    func offerAlternativeUsername () -> String {
        var username = имя пользователя
        имя пользователя + = String (Int.случайный (в: 1000 ... 9999))
        вернуть имя пользователя
    }
}

let user = User ()
user.suggestAlternativeUsername ()  

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

  пусть username = "Тайтай"

func offerAlternativeUsername () -> String {
    var username = имя пользователя
    имя пользователя + = Строка (Int.random (in: 1000 ... 9999))
    вернуть имя пользователя
}

предложениеAlternativeUsername ()  

Результат строителей

В Swift 5 неофициально появилось

конструкторов функций.1, но в ходе подготовки к Swift 5.4 они формально прошли процесс предложения Swift Evolution как SE-0289 для обсуждения и уточнения. В рамках этого процесса они были переименованы в конструкторы результатов, чтобы лучше отразить их истинное предназначение, и даже приобрели некоторые новые функции.

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

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

Вот функция, которая возвращает одну строку:

  func makeSentence1 () -> String {
    «Зачем довольствоваться герцогом, если у тебя может быть принц?»
}

печать (makeSentence1 ())  

Это отлично работает, но что, если бы мы хотели объединить несколько строк? Так же, как SwiftUI, мы можем предоставить их все индивидуально, и Swift определит это:

  // Это недействительный Swift, и он не будет компилироваться.// функция makeSentence2 () -> String {
// «Зачем довольствоваться герцогом»
// "когда можно"
// "принц?"
//}  

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

  @resultBuilder
struct SimpleStringBuilder {
    static func buildBlock (_ parts: String ...) -> String {
        части.присоединился (разделитель: "\ n")
    }
}  

Несмотря на то, что это небольшой объем кода, нужно многое распаковать:

  • Атрибут @resultBuilder сообщает Swift, что следующий тип следует рассматривать как построитель результатов. Ранее такое поведение достигалось с помощью @_functionBuilder , у которого был знак подчеркивания, чтобы показать, что он не предназначен для общего использования.
  • Каждый построитель результатов должен предоставлять по крайней мере один статический метод с именем buildBlock () , который должен принимать какие-то данные и преобразовывать их.Приведенный выше пример принимает ноль или более строк, объединяет их и отправляет обратно как одну строку.
  • Конечным результатом является то, что наша структура SimpleStringBuilder становится построителем результатов, что означает, что мы можем использовать @SimpleStringBuilder везде, где нам нужны его возможности соединения строк.

Ничто не мешает нам использовать SimpleStringBuilder.buildBlock () напрямую, например:

  let join = SimpleStringBuilder.buildBlock (
    "Зачем довольствоваться герцогом",
    "когда сможешь",
    "Принц?"
)

печать (присоединилась)  

Однако, поскольку мы использовали аннотацию @resultBuilder с нашей структурой SimpleStringBuilder , мы также можем применить это к функциям, например:

  @SimpleStringBuilder func makeSentence3 () -> String {
    "Зачем довольствоваться герцогом"
    "когда ты можешь иметь"
    "Принц?"
}

печать (makeSentence3 ())  

Обратите внимание, что нам больше не нужны запятые в конце каждой строки - @resultBuilder автоматически преобразует каждый оператор в makeSentence () в одну строку с помощью SimpleStringBuilder .

На практике построители результатов способны на значительно больше, если добавить больше методов к вашему типу построителя. Например, мы могли бы добавить поддержку if / else в наш SimpleStringBuilder , добавив два дополнительных метода, которые описывают, как мы хотим преобразовать данные. В нашем коде мы вообще не хотим преобразовывать наши строки, поэтому можем отправить их обратно:

  @resultBuilder
struct ConditionalStringBuilder {
    static func buildBlock (_ parts: String...) -> String {
        parts.joined (разделитель: "\ n")
    }

    static func buildEither (первый компонент: String) -> String {
        компонент возврата
    }

    static func buildEither (второй компонент: String) -> String {
        компонент возврата
    }
}  

Я знаю, что похоже, что мы почти не работали, но теперь наши функции могут использовать условия:

  @ConditionalStringBuilder func makeSentence4 () -> String {
    "Зачем довольствоваться герцогом"
    "когда ты можешь иметь"

    если Bool.случайный() {
        "Принц?"
    } еще {
        "Король?"
    }
}

печать (makeSentence4 ())  

Точно так же мы могли бы добавить поддержку циклов, добавив метод buildArray () к нашему типу построителя:

  @resultBuilder
struct ComplexStringBuilder {
    static func buildBlock (_ parts: String ...) -> String {
        parts.joined (разделитель: "\ n")
    }

    static func buildEither (первый компонент: String) -> String {
        компонент возврата
    }

    static func buildEither (второй компонент: String) -> String {
        компонент возврата
    }

    static func buildArray (_ components: [String]) -> String {
        компоненты.присоединился (разделитель: "\ n")
    }
}  

И теперь мы можем использовать для петель:

  @ComplexStringBuilder func countDown () -> String {
    for i in (0 ... 10) .reversed () {
        "\(я)…"
    }

    "Взлетай!"
}

печать (countDown ())  

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

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

Это особенно полезно для настраиваемых представлений SwiftUI, в которых используются построители результатов, например этот:

  struct CustomVStack : View {
    @ViewBuilder let content: Content

    var body: some View {
        VStack {
            // здесь настраиваемый функционал
            содержание
        }
    }
}  

Если вы хотите увидеть более продвинутые, реальные примеры построителей результатов в действии, вам следует заглянуть в репозиторий Awesome Function Builders на GitHub.

Локальные функции теперь поддерживают перегрузку

SR-10069 запросил возможность перегрузки функций в локальных контекстах, что на практике означает, что вложенные функции теперь могут быть перегружены, так что Swift выбирает, какую из них запускать, в зависимости от используемых типов.

Например, если мы хотим сделать несколько простых файлов cookie, мы могли бы написать такой код:

  Структурное масло {}
struct Flour {}
struct Sugar {}

func makeCookies () {
    func add (item: сливочное масло) {
        print («Добавляем масло…»)
    }

    func add (item: Мука) {
        print («Добавляем муку…»)
    }

    func add (item: Sugar) {
        print («Добавляем сахар…»)
    }

    добавить (элемент: Сливочное масло ())
    add (item: Мука ())
    добавить (элемент: Сахар ())
}  

До Swift 5.4, три метода add () могут быть перегружены, только если они не были вложены в makeCookies () , но, начиная с Swift 5.4, в этом случае также поддерживается перегрузка функций.

Swift 5.4 также позволяет нам вызывать локальные функции до их объявления, а это означает, что теперь мы можем писать такой код, если это необходимо:

  func makeCookies2 () {
    добавить (элемент: Сливочное масло ())
    add (item: Мука ())
    добавить (элемент: Сахар ())

    func add (item: сливочное масло) {
        print («Добавляем масло…»)
    }

    func add (item: Мука) {
        print («Добавляем муку…»)
    }

    func add (item: Sugar) {
        print («Добавляем сахар…»)
    }
}

makeCookies2 ()  

Оболочки свойств теперь поддерживаются для локальных переменных

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

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

  @propertyWrapper struct NonNegative  {
    значение var: T

    var wrappedValue: T {
        получить {значение}

        установленный {
            if newValue <0 {
                значение = 0
            } еще {
                значение = новое значение
            }
        }
    }

    init (wrappedValue: T) {
        if wrappedValue <0 {
            себя.значение = 0
        } еще {
            self.value = wrappedValue
        }
    }
}  

А начиная с Swift 5.4 и далее мы можем использовать эту оболочку свойства внутри обычной функции, а не просто присоединяться к свойству. Например, мы могли бы написать игру, в которой наш игрок может набирать или терять очки, но его счет никогда не должен опускаться ниже 0:

.
  func playGame () {
    @NonNegative var score = 0

    // игрок был прав
    оценка + = 4

    // игрок снова был прав
    оценка + = 8

    // игрок ошибся
    оценка - = 15

    // игрок ошибся в другом
    оценка - = 16

    печать (оценка)
}  

Пакеты теперь могут объявлять исполняемые цели

SE-0294 добавляет новую целевую опцию для приложений, использующих Swift Package Manager, что позволяет нам явно объявлять исполняемую цель.

Это особенно важно для людей, которые хотят использовать SE-0281 (используя @main для обозначения точки входа в вашу программу), потому что это не очень хорошо работает с Swift Package Manager - он всегда будет искать файл main.swift .

С этим изменением мы теперь можем удалить main.swift и использовать вместо него @main . Примечание: Вы должны указать // swift-tools-version: 5.4 в файле Package.swift, чтобы получить эту новую функциональность.

Попробовать

Свифт 5.4 доступен через Xcode 12.5, который доступен в Mac App Store.

Каких функций Swift 5.4 вы больше всего ждете?

участников в Swift: как использовать и предотвращать гонки данных

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

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

Какие актеры?

Актеры в Swift не новы: они созданы на основе модели акторов, которая рассматривает акторов как универсальные примитивы параллельных вычислений. Тем не менее, предложение SE-0306 вводит Актеров и объясняет, какую проблему они решают: Гонки данных.

Гонки данных возникают, когда к одной и той же памяти обращаются из нескольких потоков без синхронизации, и по крайней мере один доступ является записью. Гонка данных может привести к непредсказуемому поведению, повреждению памяти, нестабильным тестам и странным сбоям. У вас могут быть сбои, которые вы не можете решить сегодня, поскольку вы не знаете, когда они происходят, как вы можете их воспроизвести или как вы можете исправить их на основе теории. Моя статья Thread Sanitizer объяснила: Гонки данных в Swift подробно объясняет, как вы можете решить, найти и исправить гонки данных.

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

Вы можете определить Актера, используя ключевое слово субъект , точно так же, как если бы вы использовали класс или структуру:

  актер ChickenFeeder {
    let food = "черви"
    var numberOfEatingChickens: Int = 0
}  
Акторы

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

Актеры являются ссылочными типами, но все же отличаются от классов

Акторы - это ссылочные типы, что вкратце означает, что копии относятся к одному и тому же фрагменту данных. Следовательно, изменение копии также изменит исходный экземпляр, поскольку они указывают на один и тот же общий экземпляр. Подробнее об этом читайте в моей статье Struct vs.классы в Swift: объяснение различий.

Тем не менее, у субъектов есть важное отличие от классов: они не поддерживают наследование.

Актеры в Swift похожи на классы, но не поддерживают наследование.

Отсутствие поддержки наследования означает, что нет необходимости в таких функциях, как удобство и необходимые инициализаторы, переопределение, члены класса или операторы open и final .

Однако самая большая разница определяется основной обязанностью участников - изолировать доступ к данным.

Как актеры предотвращают скачки данных с помощью синхронизации

Акторы предотвращают скачки данных, создавая синхронизированный доступ к своим изолированным данным. Перед Актерами мы создавали тот же результат, используя всевозможные блокировки. Примером такой блокировки является параллельная очередь отправки в сочетании с барьером для обработки доступа на запись. Вдохновленный методами, описанными в моей статье Concurrent vs. Serial DispatchQueue: Concurrency in Swift объяснил, я покажу вам до и после использования Актеров.

До появления Actors мы создавали поточно-безопасную кормушку для цыплят:

  final class ChickenFeederWithQueue {
    let food = "черви"
    
    /// Комбинация частного резервного свойства и вычисляемого свойства обеспечивает синхронизированный доступ.
    частный var _numberOfEatingChickens: Int = 0
    var numberOfEatingChickens: Int {
        queue.sync {
            _numberOfEatingChickens
        }
    }
    
    /// Параллельная очередь для одновременного чтения нескольких файлов.private var queue = DispatchQueue (метка: "chicken.feeder.queue", атрибуты: .concurrent)
    
    func chickenStartsEating () {
        /// Использование барьера для остановки чтения во время записи
        queue.sync (flags: .barrier) {
            _numberOfEatingChickens + = 1
        }
    }
    
    func chickenStopsEating () {
        /// Использование барьера для остановки чтения во время записи
        queue.sync (flags: .barrier) {
            _numberOfEatingChickens - = 1
        }
    }

}  

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

С другой стороны,

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

Чтобы увидеть, как это работает, мы можем реализовать приведенный выше пример, используя ранее определенную нами кормушку для цыплят Actor:

  актер ChickenFeeder {
    let food = "черви"
    var numberOfEatingChickens: Int = 0
    
    func chickenStartsEating () {
        numberOfEatingChickens + = 1
    }
    
    func chickenStopsEating () {
        numberOfEatingChickens - = 1
    }
}  

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

Методы в Актерах изолированы для синхронизированного доступа.

То же самое происходит при доступе к изменяемому свойству numberOfEatingChickens :

Доступ к изменяемым свойствам можно получить только из Актера.

Однако нам разрешено написать следующий фрагмент кода:

  let Feder = ChickenFeeder ()
печать (податчик.питание)  

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

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

Использование async / await для доступа к данным от Актеров

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

В Swift мы можем создать асинхронный доступ, используя ключевое слово await :

  let Feder = ChickenFeeder ()
awaitfeder.chickenStartsEating ()
print (await feeder.numberOfEatingChickens) // Выводит: 1  

Предотвращение ненужных приостановок

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

Чтобы лучше понять эту концепцию, давайте рассмотрим случай, в котором вы хотите объединить операции в один метод, чтобы предотвратить дополнительные приостановки. Например, представьте, что у нашего актера есть метод уведомления, который уведомляет наблюдателей о новой курице, которая начала есть:

  extension ChickenFeeder {
func notifyObservers () {
NotificationCenter.default.post (имя: NSNotification.Name ("chicken.started.eating"), объект: numberOfEatingChickens)
}
}  

Мы могли бы использовать этот код, дважды используя await :

  let Feder = ChickenFeeder ()
жду фидера.курицаStartsEating ()
await feeder.notifyObservers ()  

Однако это может привести к двум точкам приостановки, по одной на каждую await . Вместо этого мы могли бы оптимизировать этот код, вызвав метод notifyObservers изнутри chickenStartsEating :

.
  func chickenStartsEating () {
numberOfEatingChickens + = 1
notifyObservers ()
}  

Поскольку мы уже находимся внутри Актера с синхронизированным доступом, нам не нужно еще await .Это важные улучшения, которые следует учитывать, поскольку они могут повлиять на производительность.

Неизолированный доступ внутри Актеров

Важно понимать концепцию изоляции внутри Актеров. В приведенных выше примерах уже показано, как синхронизируется доступ из экземпляров внешних субъектов, требуя использования await . Однако при внимательном рассмотрении вы могли заметить, что наш метод notifyObservers не требует использования await для доступа к нашему изменяемому свойству numberOfEatingChickens .

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

Однако есть случаи, когда вы знаете, что изолированного доступа не требуется. По умолчанию методы в акторах изолированы. Следующий метод обращается только к нашему неизменяемому свойству food , но по-прежнему требует await для доступа к нему:

  let Feder = ChickenFeeder ()
жду фидера.printWhatChickensAreEating ()  

Это странно, поскольку мы знаем, что не имеем доступа ни к чему, требующему синхронизированного доступа. SE-0313 был введен для решения именно этой проблемы. Мы можем пометить наш метод ключевым словом nonisolated , чтобы сообщить компилятору Swift, что наш метод не обращается к каким-либо изолированным данным:

  extension ChickenFeeder {
неизолированная функция printWhatChickensAreEating () {
print ("Цыплята едят \ (еду)")
}
}

let feeder = ChickenFeeder ()
кормушка.printWhatChickensAreEating ()  

Обратите внимание, что вы также можете использовать неизолированное ключевое слово для вычисляемых свойств, что полезно для соответствия таким протоколам, как CustomStringConvertible :

  extension ChickenFeeder: CustomStringConvertible {
    неизолированное описание var: String {
        «Кормушка для цыплят \ (еда)»
    }
}  

Однако определение их для неизменяемых свойств не требуется, поскольку компилятор сообщит вам:

Пометка неизменяемых свойств неизолированными является излишней.

Почему при использовании Актеров все еще могут возникать гонки данных

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

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

  queueOne.async {
awaitfeder.chickenStartsEating ()
}
queueTwo.async {
print (ожидание Feder.numberOfEatingChickens)
}  

Состояние гонки здесь определяется как: «какой поток будет первым, кто запустит изолированный доступ?». Итак, есть два основных результата:

.
  • Первая очередь идет первой, увеличивая количество поедающих цыплят. Очередь 2 напечатает 1
  • Очередь 2 будет первой, напечатав количество съеденных цыплят, которое все еще равно 0

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

Продолжение пути к Swift Concurrency

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

Заключение

Swift Actors решает проблему гонки данных, которая была обычной проблемой в приложениях, написанных на Swift. Доступ к изменяемым данным осуществляется синхронно, что обеспечивает их безопасность.Мы не рассматривали экземпляр MainActor , который является отдельной темой. Я обязательно расскажу об этом в следующей статье. Надеюсь, вы смогли проследить и узнать, как использовать Актеров в своих приложениях.

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

Спасибо!

React Native против Swift: что лучше подходит для разработки MVP?

Однажды стартап поспорил, что он сможет написать кратчайший рассказ, который сможет кого-нибудь тронуть.Он выиграл пари: «Продается приложение для iOS, написанное на Swift». В Purrweb не любят грустить, поэтому мы используем React Native. Кросс-платформенный фреймворк позволяет быстро писать код, подходящий для iOS и Android. В этой статье мы рассмотрим другие преимущества React Native и сравним их со Swift, родным языком Apple. Добро пожаловать на дуэль React Native vs Swift!

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

Собственная разработка

Собственные приложения разрабатываются только для одной операционной системы.Такое приложение создается с использованием языков программирования и инструментов, специфичных для одной платформы. Например, вы можете разработать приложение для Android на Java или Kotlin, а для iOS выбрать Swift и Objective-C.

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

Кросс-платформенная разработка

Кросс-платформенная разработка - это процесс создания приложения, которое работает на нескольких платформах. Кроссплатформенность использует такие инструменты, как React Native, Xamarin и Flutter. Приложения, написанные с использованием этих технологий, можно развертывать как на Android, так и на iOS.

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

Purrweb специализируется на создании MVP. MVP - это минимально жизнеспособный продукт, другими словами, приложение, ограниченное до основных функций, без излишеств UI / UX и сложной разработки. Стартапу нужен MVP, как человеку нужна вода, потому что он помогает представить идею инвесторам и получить средства для дальнейшего развития.Здесь вам просто нужно быстро и без дополнительных вложений разработать «первую версию» приложения, поэтому кроссплатформенная разработка и MVP идут рука об руку.

Android или iOS?

Когда дело доходит до собственных приложений, вам нужно выбрать, какая операционная система будет первой. Так начинается битва между React Native и Swift. Вкратце: для iOS. Пользователи этой операционной системы привыкли платить за контент и приложения. Ребята с iPhone также являются лидерами мнений, поэтому показ им MVP в первую очередь выгоден для стартапа.

Но этот план звучит как «трата времени и денег»

Если вам все еще нужно сначала написать приложение для iOS, мы советуем вам сделать это в React Native. Это сэкономит вам время не только на поиск и подключение новой команды, но и на разработку второго приложения. В результате вы получите кроссплатформенный MVP, который можно легко заменить на обе платформы. Прохладный? Конечно!

Почему React Native?

В битве между React Native и Swift за стартап побеждает React Native.И не потому, что мы используем этот язык в наших проектах - здесь все честно! Вот некоторые из преимуществ, которые стартап оценит на ранних стадиях разработки проекта.

  • Все еще экономя деньги и время

Мы постоянно повторяем, насколько хорошо React Native выполняет работу по «экономии как можно большего количества ресурсов». Время, деньги и усилия стартапа, которые тратятся на поиск, адаптацию , и работа с родными командами. А потом эти команды - хорошо, если параллельно - берутся за разработку, создают приложение, вносят в него доработки, тестируют, редактируют, тестируют, редактируют… Ну, вы поняли.

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

  • Еще немного об экономии

Кроме того, разработчики iOS, как правило, получают высокие зарплаты, в то время как разработчики кроссплатформенных мобильных устройств взимают с вас меньшую плату. Например, разработчик Android должен будет заплатить 1500 долларов, а разработчик React Native - в три раза меньше.Обстреливает артиллерийским огнем!

Код, написанный на React Native, легко «перезагрузить» для любой платформы, будь то iOS или Android. Повторное использование кода намного проще, чем написание нового, и это ВСЕ ЕЩЕ экономит время и деньги стартапа. Интересный факт: код, написанный на React Native для iOS, не будет сильно отличаться от нативного.

  • Низкий порог вхождения в технологию

Когда мы спрашиваем, что лучше - React Native или Swift, - наши разработчики говорят, что JavaScript и фреймворк React Native легче освоить, чем Swift.Если команда уже пишет веб-приложения на React, то научиться создавать кроссплатформенные приложения для мобильных устройств не составит труда.

Многие разработчики интерфейсов знакомы с технологиями HTML, CSS, JavaScript и React. А React Native - это JS-фреймворк. И пусть RN не использует HTML для рендеринга приложения, а предоставляет набор компонентов, подобных HTML. React Native использует таблицы стилей JS для стилизации компонентов, которые также похожи на обычные таблицы CSS.

Глеб Комаров,
фронтенд-разработчик в Purrweb

  • Возможность добавлять собственные элементы

Instagram - яркий пример приложения. с родными элементами.Несмотря на то, что приложение написано на React Native, внутри много нативных элементов. Дело в том, что части нативного кода легко интегрируются в React Native, а это улучшает качество приложения.

По проекту EnerGO возникло желание заказчика: реализовать привязку кредитной карты с помощью Google Pay и Apple Pay и проводить платежи через платежную систему CloudPayments. У React Native большое сообщество разработчиков, но для него нет готовых библиотек и SDK (средств разработки).Мы решили, что напишем библиотеку для React Native сами. К счастью, архитектура фреймворка позволяет использовать собственный код в любом проекте.

Антон Вотинов,
фронтенд-разработчик в Purrweb

Приложения Purrweb React Native

В Purrweb мы делаем выдающиеся MVP с React Native. В этой области у нас есть хороший опыт, поэтому в этой статье мы сделали подборку наших приложений. Мы еще не написали наши Instagram, Skype или UberEats, но реализовали пару интересных проектов (на самом деле их количество уже давно перевалило за сотню).Давайте поговорим о ярких примерах нашей работы с React Native.

А здесь вы найдете 20 лучших приложений на React Native - обновленная версия 2021 года, приходите за вдохновением 🤗

Tunetank

Возможно, вы уже видели рекламу этого приложения на YouTube - ребята, есть вырос из MVP до действительно крутого приложения и уже запустил рекламную кампанию. TuneTank предоставляет клиентам возможность приобрести лицензию на любой трек для дальнейшего коммерческого использования.Для музыкантов TuneTank - альтернативный источник дохода. Сайт позволяет загружать песни, продавать на них лицензию, а также обеспечивает защиту авторских прав и помогает в продвижении.

Talentum

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

EnerGO

Разработка мобильных приложений для китайского оборудования похожа на первую велопробег. Обычно вы понимаете, как крутить педали, но на этот раз вам придется ездить на велосипеде по китайским дорогам - вы не можете понять, как заставить все это работать вместе, чтобы получать удовольствие от процесса. Развитие Энерго.EnerGO - это стартап, который делает аренду пауэрбанков доступной в московском метро и кафе: достаточно взять с одной станции и бросить на другой.

EyeBuy

Когда мы делали EyeBuy, аналогов такого приложения в России еще не было. Предупреждение о спойлере: пока нет. Индустрия прямых трансляций покупок переезжает к нам из Китая, но еще не приобрела необходимой популярности. Покупать товары прямо в потоке - это круто, не правда ли? В EyeBuy мы реализовали возможность добавлять товары в корзину, пока поток еще продолжается - чтобы ничего не потерять.Пилот приложения был протестирован сразу на крупных брендах, на стрим прилетело 500 зрителей.

Lytic

Lytic - замечательный стартап, который пришел к нам с 1,5 тыс. Долларов и ушел с 400 тыс. Долларов. Идея сервиса такова: если человека что-то беспокоит, он может написать свои симптомы в приложении. Чат-бот задаст уточняющие вопросы и расскажет о причинах плохого самочувствия. После этого приложение порекомендует, какие анализы вам нужно сдать, и предложит записаться на прием к врачу, который специализируется на этих заболеваниях.Интересно, скачали бы вы такое приложение? Мы бы были да!

Заключение

React Native vs Swift - RN больше подходит для стартапов

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

Много хороших примеров

Instagram, Skype, Walmart, Tesla, Facebook, Wix - это неполный список приложений, написанных на React Native. Помимо известных гигантов, в портфолио Purrweb только более сотни успешных проектов с этим фреймворком. У нас есть целая команда - более 50! - специалисты, которые работают с технологиями несколько лет и за три месяца сделают крутой MVP для вашего стартапа!

Что нового в Swift?

SE-0304 представляет целый ряд подходов к выполнению, отмене и мониторингу параллельных операций в Swift и основывается на работе, представленной последовательностями async / await и async.

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

  перечисление LocationError: Error {
    случай неизвестен
}

func getWeatherReadings (для местоположения: String) async throws -> [Double] {
    сменить местоположение {
    корпус «Лондон»:
        возврат (1...100) .map {_ в Double.random (in: 6 ... 26)}
    корпус «Рим»:
        return (1 ... 100) .map {_ в Double.random (in: 10 ... 32)}
    дело «Сан-Франциско»:
        return (1 ... 100) .map {_ в Double.random (in: 12 ... 20)}
    дефолт:
        бросить LocationError.unknown
    }
}

func fibonacci (of number: Int) -> Int {
    var first = 0
    var second = 1

    для _ в 0 .. <число {
        пусть предыдущий = первый
        первый = второй
        второй = предыдущий + первый
    }

    вернуться первым
}  

Простейший асинхронный подход, представленный структурированным параллелизмом, - это возможность использовать атрибут @main для немедленного перехода в асинхронный контекст, что делается просто путем пометки метода main () значением async , например:

  @ главная
struct Main {
    static func main () async throws {
        let readings = попробуйте await getWeatherReadings (для: "Лондон")
        print ("Показания: \ (показания)")
    }
}  

Основные изменения, внесенные структурированным параллелизмом, поддерживаются двумя новыми типами, Task и TaskGroup , которые позволяют нам выполнять параллельные операции индивидуально или скоординированно.

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

Итак, мы можем вызвать fibonacci (of :) много раз в фоновом потоке, чтобы вычислить первые 50 чисел в последовательности:

  func printFibonacciSequence () async {
    let task1 = Task {() -> [Int] в
        var числа = [Int] ()

        для я в 0.. <50 {
            пусть результат = фибоначчи (из: i)
            numbers.append (результат)
        }

        вернуть числа
    }

    let result1 = await task1.value
    print ("Первые 50 чисел в последовательности Фибоначчи: \ (результат1)")
}  

Как видите, мне нужно было явно написать Task {() -> [Int] в , чтобы Swift понимал, что задача вернется, но если ваш код задачи проще, в этом нет необходимости. Например, мы могли написать это и получить точно такой же результат:

  let task1 = Task {
    (0.. <50) .map (фибоначчи)
}  

Опять же, задача запускается, как только она была создана, и функция printFibonacciSequence () продолжит работу в каком бы потоке она ни была, пока вычисляются числа Фибоначчи.

Совет: Операция нашей задачи - это закрытие без выхода, потому что задача запускает ее сразу, а не сохраняет на потом. Это означает, что если вы используете Task внутри класса или структуры, вам не нужно использовать self. для доступа к свойствам или методам.

Когда дело доходит до чтения законченных чисел, await task1.value гарантирует, что выполнение printFibonacciSequence () приостанавливается до тех пор, пока вывод задачи не будет готов, после чего он будет возвращен. Если вам все равно, что возвращает задача - если вы просто хотите, чтобы код запускался и заканчивался всякий раз, - вам не нужно нигде хранить задачу.

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

  func runMultipleCalculations () async throws {
    let task1 = Task {
        (0 .. <50) .map (фибоначчи)
    }

    let task2 = Task {
        попробуйте await getWeatherReadings (для: "Рим")
    }

    let result1 = await task1.value
    let result2 = попробуйте await task2.value
    print ("Первые 50 чисел в последовательности Фибоначчи: \ (результат1)")
    print ("Погода в Риме: \ (результат2)")
}  

Swift предоставляет нам встроенные приоритеты задач: высокий , по умолчанию , низкий и фон .В приведенном выше коде он не устанавливается специально, поэтому он получит по умолчанию , но мы могли бы указать что-то вроде Task (priority: .high) , чтобы настроить это. Если вы пишете только для платформ Apple, вы также можете использовать более знакомые приоритеты userInitiated вместо высокого и утилиту вместо low , но вы не можете получить доступ к userInteractive , потому что это зарезервировано для основного потока.

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

  • Вызов Task.sleep () переведет текущую задачу в спящий режим на определенное количество наносекунд. Пока не появится что-то лучшее, это означает, что 1_000_000_000 будет означать 1 секунду.
  • Вызов Task.checkCancellation () проверит, запрашивал ли кто-то отмену этой задачи, вызвав его метод cancel () , и если да, то выдаст CancellationError .
  • Вызов Task.yield () приостанавливает текущую задачу на некоторое время, чтобы дать некоторое время любым задачам, которые могут ожидать, что особенно важно, если вы выполняете интенсивную работу в цикле.

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

  func cancelSleepingTask () async {
    let task = Task {() -> Строка в
        print ("Запуск")
        попробуйте await Task.sleep (наносекунды: 1_000_000_000)
        попробуйте Task.checkCancellation ()
        вернуть "Готово"
    }

    // Задача началась, но мы ее отменим, пока она спит
    task.cancel ()

    делать {
        let result = try await task.ценить
        print ("Результат: \ (результат)")
    } ловить {
        print («Задача была отменена.»)
    }
}  

В этом коде Task.checkCancellation () поймет, что задача была отменена, и немедленно выдаст CancellationError , но это не дойдет до нас, пока мы не попытаемся прочитать task.value .

Совет: Используйте task.result , чтобы получить значение Result , содержащее значения успеха и неудачи задачи. Например, в приведенном выше коде мы вернем результат .Это , а не , требует вызова try , потому что вам все еще нужно обрабатывать случай успеха или неудачи.

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

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

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

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

  func printMessage () async {
    let string = await withTaskGroup (of: String.self) {группа -> Строка в
        group.addTask {"Привет"}
        group.addTask {"От"}
        group.addTask {"A"}
        group.addTask {"Задача"}
        group.addTask {"Группа"}

        var Собранные = [Строка] ()

        для значения ожидания в группе {
            collect.append (значение)
        }

        возврат собран. соединен (разделитель: "")
    }

    печать (строка)
}  

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

Совет: Все задачи в группе задач должны возвращать один и тот же тип данных, поэтому для сложной работы вам может потребоваться вернуть перечисление со связанными значениями, чтобы получить именно то, что вы хотите. Более простая альтернатива представлена ​​в отдельном предложении Async Let Bindings.

Каждый вызов addTask () может быть любой функцией, которая вам нравится, если результатом будет строка.Однако, хотя группы задач автоматически ожидают завершения всех дочерних задач перед возвратом, когда этот код запускается, это немного подбрасывает то, что он будет печатать, потому что дочерние задачи могут выполняться в любом порядке - мы с большей вероятностью получим « Привет от группы задач A », а мы, например,« Привет от группы задач ».

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

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

  func printAllWeatherReadings () async {
    делать {
        print («Расчет средней погоды…»)

        let result = try await withThrowingTaskGroup (of: [Double].self) {группа -> Строка в
            group.addTask {
                попробуйте await getWeatherReadings (для: "Лондон")
            }

            group.addTask {
                попробуйте await getWeatherReadings (для: "Рим")
            }

            group.addTask {
                попробуйте await getWeatherReadings (для: "Сан-Франциско")
            }

            // Преобразуем наш массив массивов в единый массив двойников
            let allValues ​​= попробуйте await group.reduce ([], +)

            // Рассчитываем среднее значение всех наших удвоений
            пусть среднее = все значения.уменьшить (0, +) / Double (allValues.count)
            return "Общая средняя температура \ (средняя)"
        }

        print ("Готово! \ (результат)")
    } ловить {
        print ("Ошибка вычисления данных.")
    }
}  

В этом случае каждый из вызовов addTask () идентичен, за исключением передаваемой строки местоположения, поэтому вы можете использовать что-то вроде для местоположения в [«Лондон», «Рим», «Сан-Франциско»] { для вызова addTask () в цикле.

Группы задач имеют метод cancelAll () , который отменяет любые задачи внутри группы, но с помощью addTask () после этого продолжит добавлять работу в группу.В качестве альтернативы вы можете использовать addTaskUnlessCancelled () , чтобы пропустить добавление работы, если группа была отменена - проверьте возвращенное логическое значение, чтобы узнать, была ли работа добавлена ​​успешно или нет.

оберток недвижимости в Swift | Swift by Sundell

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

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

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

Как следует из названия, оболочка свойств - это, по сути, тип, который обертывает заданное значение, чтобы присоединить к нему дополнительную логику, и может быть реализован с использованием структуры или класса, аннотируя его с помощью @propertyWrapper атрибут. Кроме того, единственное реальное требование состоит в том, чтобы каждый тип оболочки свойства содержал хранимое свойство с именем wrappedValue , которое сообщает Swift, какое базовое значение обертывается.

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

  @propertyWrapper struct Capitalized {
    var wrappedValue: String {
        didSet {wrappedValue = wrappedValue.capitalized}
    }

    init (wrappedValue: String) {
        self.wrappedValue = wrappedValue.capitalized
    }
}  

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

Чтобы применить нашу новую оболочку свойств к любому из наших свойств String , нам просто нужно аннотировать его с помощью @Capitalized - и Swift автоматически сопоставит эту аннотацию с нашим вышеупомянутым типом. Вот как мы можем это сделать, чтобы гарантировать, что свойства firstName и lastName типа User всегда пишутся с заглавной буквы:

  struct User {
    @Capitalized var firstName: String
    @Capitalized var lastName: String
}  

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

 
var user = User (firstName: "john", lastName: "appleseed")


Пользователь.lastName = "sundell"  

Точно так же, если оболочка свойств определяет инициализатор init (wrappedValue :) (как это делает наш тип Capitalized ) - тогда мы даже можем изначально назначать значения по умолчанию нашим обернутым свойствам, например это:

  struct Document {
    @Capitalized var name = "Документ без названия"
}  

Таким образом, оболочки свойств позволяют нам прозрачно обертывать и изменять любое сохраненное свойство - используя комбинацию типа с пометкой @propertyWrapper и аннотаций, соответствующих имени этого типа.Но это только начало.

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

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

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

  @propertyWrapper struct UserDefaultsBacked  {
    let ключ: String
    хранилище var: UserDefaults = .standard

    var wrappedValue: Значение? {
        получить {storage.value (forKey: ключ) как? Ценить }
        set {storage.setValue (newValue, forKey: ключ)}
    }
}  

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

  struct SettingsViewModel {
    @UserDefaultsBacked  (ключ: «отметить как прочитанное»)
    var autoMarkMessagesAsRead

    @UserDefaultsBacked  (ключ: "размер страницы поиска")
    var numberOfSearchResultsPerPage
}  

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

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

  extension UserDefaults {
    static var shared: UserDefaults {
        let комбинированный = UserDefaults.standard
        комбинированный.addSuite (с названием: "group.johnsundell.app")
        возврат вместе
    }
}

struct SettingsViewModel {
    @UserDefaultsBacked  (ключ: «пометить как прочитанное», хранилище: .shared)
    var autoMarkMessagesAsRead

    @UserDefaultsBacked  (ключ: "размер-страницы-поиска", хранилище: .shared)
    var numberOfSearchResultsPerPage
}  

Дополнительные сведения об использовании UserDefaults для обмена данными между несколькими приложениями см. В разделе «Возможности UserDefaults в Swift».

Однако наша реализация выше имеет довольно существенный недостаток.Несмотря на то, что оба вышеупомянутых свойства объявлены как необязательные, их фактические значения все равно будут необязательными, поскольку наш тип UserDefaultsBacked указывает значение Value? как тип свойства wrappedValue .

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

  @ propertyWrapper struct UserDefaultsBacked  {
    var wrappedValue: Value {
        получать {
            let value = storage.value (forKey: key) как? Ценить
            возвращаемое значение ?? значение по умолчанию
        }
        установленный {
            место хранения.setValue (новоеЗначение, forKey: ключ)
        }
    }

    закрытый ключ let: String
    private let defaultValue: Значение
    частное хранилище let: UserDefaults

    init (wrappedValue defaultValue: значение,
         ключ: строка,
         хранилище: UserDefaults = .standard) {
        self.defaultValue = defaultValue
        self.key = ключ
        self.storage = хранилище
    }
}  

Теперь мы можем превратить оба наших свойства в неопциональные, например:

  struct SettingsViewModel {
    @UserDefaultsBacked (ключ: «отметить как прочитанное»)
    var autoMarkMessagesAsRead = true

    @UserDefaultsBacked (ключ: "размер страницы поиска")
    var numberOfSearchResultsPerPage = 20
}  

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

Чтобы решить эту проблему, давайте также добавим удобный API в нашу оболочку для случаев, когда его тип Value соответствует ExpressibleByNilLiteral (что делает Optional ) - в который мы автоматически вставим nil в качестве значения по умолчанию:

  extension UserDefaultsBacked, где Value: ExpressibleByNilLiteral {
    init (ключ: String, хранилище: UserDefaults =.стандарт) {
        self.init (wrappedValue: nil, ключ: ключ, хранилище: хранилище)
    }
}  

С внесенными выше изменениями мы теперь можем свободно использовать нашу оболочку UserDefaultsBacked как с необязательными, так и с необязательными значениями:

  struct SettingsViewModel {
    @UserDefaultsBacked (ключ: «отметить как прочитанное»)
    var autoMarkMessagesAsRead = true

    @UserDefaultsBacked (ключ: "размер страницы поиска")
    var numberOfSearchResultsPerPage = 20

    @UserDefaultsBacked (ключ: «подпись»)
    var messageSignature: String?
}  

Однако есть еще одна вещь, которую мы должны принять во внимание, поскольку теперь мы сможем присвоить nil свойству UserDefaultsBacked .Чтобы избежать сбоев в таких ситуациях, нам нужно будет обновить нашу оболочку свойств, чтобы сначала проверить, равно ли какое-либо назначенное значение nil , прежде чем продолжить сохранение его в текущем экземпляре UserDefaults , например:

 
частный протокол AnyOptional {
    var isNil: Bool {get}
}

extension Необязательно: AnyOptional {
    var isNil: Bool {self == nil}
}

@propertyWrapper struct UserDefaultsBacked <значение> {
    var wrappedValue: Value {
        получать { ... }
        установленный {
            если let optional = newValue as? AnyOptional, необязательно.isNil {
                storage.removeObject (forKey: ключ)
            } еще {
                storage.setValue (новоеЗначение, forKey: ключ)
            }
        }
    }
    
    ...
}  

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

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

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

  @propertyWrapper final class Flag  {
    var wrappedValue: Value
    пусть имя: Строка

    fileprivate init (wrappedValue: Value, имя: String) {
        себя.wrappedValue = wrappedValue
        self.name = имя
    }
}  

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

  struct FeatureFlags {
    @Flag (имя: "функция-поиск")
    var isSearchEnabled = false

    @Flag (название: "эксперимент-примечание-предел")
    var maximumNumberOfNotes = 999
}  

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

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

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

  private struct FlagCodingKey: CodingKey {
    var stringValue: String
    var intValue: Int?

    init (имя: String) {
        stringValue = имя
    }
    
    

    init? (stringValue: String) {
        себя.stringValue = stringValue
    }

    init? (intValue: Int) {
        self.intValue = intValue
        self.stringValue = Строка (intValue)
    }
}  

Далее нам понадобится способ ссылаться на каждый из наших флагов, не зная их общий тип - но вместо того, чтобы прибегать к полному стиранию типа, мы собираемся добавить протокол под названием DecodableFlag , который: Я разрешу каждому флагу декодировать собственное значение в соответствии с его Value type:

  private protocol DecodableFlag {
    typealias Контейнер = KeyedDecodingContainer 
    func decodeValue (из контейнера: Контейнер) выбрасывает
}  

Теперь мы сможем написать наш код декодирования, сделав наш тип Flag условно соответствующим нашему новому протоколу DecodableFlag всякий раз, когда его общий тип Value декодируется:

  extension Flag: DecodableFlag, где Value: Decodable {
    fileprivate func decodeValue (из контейнера: Container) выбрасывает {
        let key = FlagCodingKey (имя: имя)

        
        if let value = try container.decodeIfPresent (Value.self, forKey: key) {
            wrappedValue = значение
        }
    }
}  

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

  extension FeatureFlags: Decodable {
    init (от decoder: Decoder) выбрасывает {
        let container = попробуйте декодер.контейнер (keyedBy: FlagCodingKey.self)

        для ребенка в зеркале (отражение: себя) .children {
            охранник let flag = child.value как? DecodableFlag else {
                Продолжить
            }

            попробуйте flag.decodeValue (from: container)
        }
    }
}  

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

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

Однако иногда нам может потребоваться получить доступ к самой оболочке свойств, а не к значению, которое она обертывает. Это особенно часто встречается при создании пользовательских интерфейсов с использованием новой инфраструктуры SwiftUI от Apple, которая интенсивно использует оболочки свойств для реализации различных API-интерфейсов привязки данных.

Например, здесь мы создаем QuantityView , который позволяет указывать некоторую форму количества с помощью представления Stepper . Чтобы привязать этот фрагмент состояния к нашему представлению, мы аннотировали его с помощью @State , а затем даем нашему шаговому прямому доступу к этому обернутому состоянию (а не только к его текущему значению Int ), передав с префиксом $ - вот так:

  struct QuantityView: View {
    ...
    @State private var количество = 1

    var body: some View {
        
        Степпер ("Количество: \ (количество)",
            значение: количество $,
            в 1...99
        )
    }
}  

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

  @propertyWrapper final class Flag  {
    var projectedValue: Flag {self}
    ...
}  

Точно так же любое аннотированное свойство Flag теперь также может быть передано как прогнозируемое значение, то есть как ссылка на саму его оболочку. Опять же, это не то, что связано со SwiftUI, на самом деле мы могли бы принять такой же шаблон и при использовании UIKit - например, если UIViewController принимает экземпляр Flag при инициализации.

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

  class FlagToggleViewController: UIViewController {
    частный флаг let: Flag 
    частный ленивый var label = UILabel ()
    приватный ленивый var toggle = UISwitch ()

    init (flag: Flag ) {
        себя.flag = флаг
        super.init (nibName: nil, bundle: nil)
    }
    
    ...

    переопределить функцию viewDidLoad () {
        super.viewDidLoad ()

        label.text = flag.name
        toggle.isOn = flag.wrappedValue

        toggle.addTarget (сам,
            действие: #selector (toggleFlag),
            для: .valueChanged
        )
        
        ...
    }

    @objc private func toggleFlag () {
        flag.wrappedValue = toggle.isOn
    }
}  

Для инициализации вышеуказанного контроллера представления мы будем использовать тот же синтаксис на основе префиксов $ , что и при передаче ссылки @State при использовании SwiftUI:

  let flags: FeatureFlags =...

пусть searchToggleVC = FlagToggleViewController (
    flag: flags. $ isSearchEnabled
)  

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

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

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

Добавить комментарий

Ваш адрес email не будет опубликован.