Это перевод статьи Concurrency Step-by-Step: Stateful Systems
В предыдущих первом и во втором постах я использовал исключительно систему только для чтения. Это далеко от реальных задач! Реальные приложения пишут данные в локальное хранилище, в удаленные сервисы и, как правило, находятся «по самые уши» в изменяемом состоянии.
В этом посте мы собираемся создать приложение SwiftUI, которое работает с изменяемым состоянием, размещенным на (мнимой) удаленной сетевой службе.
Краткие заметки
Как и во всех предыдущих постах этой серии, я буду игнорировать ошибки и требовать Xcode 16. Я также остаюсь новичком в SwiftUI, а здесь больше SwiftUI, чем в других постах.
Еще одно важное замечание заключается в том, что я пытался найти подходящую бесплатную удаленную службу, но безуспешно. Сначала я думал, что это будет решающим фактором. Но потом я понял, что это может быть счастливой случайностью. Читайте дальше, чтобы узнать почему!
«Удаленная» (‘remote’) система
Для начала нам нужна какая-то удаленная (remote) служба для взаимодействия. Весь смысл этого упражнения — иметь дело с состоянием, поэтому важно, чтобы эта система сохраняла состояние. Но я не смог ее найти, поэтому мы просто притворимся.
final class RemoteSystem: @unchecked Sendable {
private var state = false
private let queue = DispatchQueue(label: "RemoteSystemQueue")
func toggleState(completionHandler: @escaping @Sendable () -> Void) {
queue.async {
self.state.toggle()
completionHandler()
}
}
func readState(completionHandler: @escaping @Sendable (Bool) -> Void) {
queue.async {
completionHandler(self.state)
}
}
}
Это симуляция “удаленной” системы, которая управляет значением ровно одной булевой Bool
переменной var state
. Внешний мир может переключать или считывать текущее булевское Bool
значение этой переменной state
, но он должен делать это асинхронно.
Я уверен, вы также заметили, что я решил реализовать это с помощью Dispatch. Чтобы это работало со Swift 6, мы должны сообщить компилятору, что мы взяли на себя ответственность за потокобезопасность, отметив ТИП RemoteSystem
как @unchecked Sendable
. Нам также нужно несколько @Sendable
замыканий.