Перейти к содержанию

4. Sendable


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


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

Гонка данных (Напоминание)

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

  • Непредсказуемое поведение
  • Повреждение памяти
  • Ненадежные тесты
  • Странные сбои

STRICT CONCURRENCY

Понимая, что проблема Data Race может усугубиться с внедрением async/await - команда swift внедрила различные проверки на этапе компиляции кода, которые подсказывают разработчикам о возможной гонке данных. Если вы начали внедрять async/await и не видите никаких предупреждений, то вероятнее всего у вас стоит низкий уровень проверки компилятора. Чтобы включить полную проверку компилятора - необходимо зайти в Build Settings -> SWIFT_STRICT_CONCURRENCY = complete

strictConcurrency.avif

Sendable

Если обратиться к официальной документации swift, то

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

Sendable + Struct, Enum

Чтобы структура удовлетворяла протоколу Sendable, необходимо, чтобы все проперти были Sendable. Если вы понимаете, что в будущем ваша структура будет изменяться и может появиться новое изменяемое проперти внутри и при этом вам необходимо, чтобы структура была Sendable, то лучше сразу её пометить Sendable

Есть также неявное соответствие протоколу Sendable.

  • @frozen структуры и енумы
  • Структуры и перечисления, которые не являются public и не помечены как @usableFromInline.

Sendable + Class

Для того, чтобы класс удовлетворял протоколу Sendable, необходимо, чтобы:

  • Он был помечен final
  • Содержать только stored properties, которые не изменяемы и также помечены Sendable
  • Не должен иметь родительского класса и не должен наследоваться от NSObject

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

Sendable + Actors

Все типы экторов - удовлетворяют протоколу Sendable. (по определению actor)

Sendable + Функции, кложуры

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

let sendableClosure = { @Sendable (number: Int) -> String in
    if number > 12 { 
        return "More than a dozen."
    } else { 
        return "Less than a dozen" 
    } 
}

Sendable + Tuples

Кортеж является Sendable, только в том случае если все его элементы являются Sendable

Sendable + Примитивы

Все метатипы такие как Int, Bool и другие по умолчанию Sendable.

Unchecked Sendable

Отключает проверки компилятора в данном классе/структуре. Написав unchecked sendable вы полностью берёте ответственность на себя, говоря компилятору: "Я уверен, что всё, что находится внутри - готово к работе с асинхронным контекстом и проблем с гонками данных не возникнет"

Команда swift не рекомендует использовать часто @unchecked Sendable, чтобы случайно не отключить нужные проверки.

Итог

Хочется сказать, что в первую очередь Sendable нужен именно нам (разработчикам), чтобы мы могли выстраивать правильный код, который при расширении в дальнейшем не вызывал бы проблем. Поэтому я настоятельно рекомендую обдумывать все ворнинги компилятора и быть осторожными, когда вы пишите @unchecked Sendable