
Комментарии 6
Вижу что мобильные приложения, там полегче в плане с "вы оффлайн".
Но я никогда не забуду, как клиент нам звонил и жаловался, что не работает наш сайт, а в итоге оказалось, что у них со вчера нет света в офисе, он сидит с ноутбука. Но интернет воткнул офисный, который естественно не работает.
Для тех, кто придумал "Что-то пошло не так" в новомодных приложениях котел уже греют?
С этим трендами очень актуальным становится продумать как будет жить приложение в offline
и года не прошло как начали догадываться. и без интернетов то непонятно: накой вообще новая учетка на всякий чих (приложение). а они еще и гонят меабайт данных там где требуется 100 байт передать
Спасибо за статью эту и предыдущие! Мне очень нравится Ваш слог, пожалуйста, продолжайте :)
Особенно нравится стиль перехода к выводам почти в каждом абзаце и, главное, их меткость.
По этой статье пара предложений:
init() {
monitor.pathUpdateHandler = { [weak self] path in
DispatchQueue.main.async {
self?.isConnected = path.status == .satisfied
}
}
monitor.start(queue: queue)
}1) Оставить один стиль, не смешивая GCD и async-await: в дальнейшем в статье последний используется;
2) Не в init'е стартовать, а отдельными методами рулить старт/стоп
Суммарно приблизительный вариант "быстро-на-коленке"
@Observable
final class NetworkMonitor {
// Добавил private(set) ибо не считаю, что нужно разрешать извне менять состояние
private(set) var isConnected: Bool
// либо не Never, а ошибку наружу давать, если потребуется
@ObservationIgnored
private var monitoringTask: Task<Void, Never>?
@ObservationIgnored
private var monitor: NWPathMonitor
init(monitor: NWPathMonitor) {
// возможно, DI Monitor'а под протоколом
self.monitor = monitor
}
func startMonitoring() {
if monitoringTask != nil { return }
monitoringTask = Task(priority: .high /* или другой */) { [weak self] in
guard let monitor = self?.monitor else { return }
// Ключевой момент: NWPathMonitor.Iterator: AsyncIteratorProtocol
for await path in monitor {
guard let self = self, !Task.isCancelled else { return }
self.isConnected = path.status == .satisfied
}
}
}
func stopMonitoring() {
monitoringTask?.cancel()
}
deinit {
stopMonitoring()
}
}Нужен персистентный store: Core Data, SQLite, или хотя бы
UserDefaultsдля простых случаев.
3) Некритично: предлагаю упомянуть как SwiftData, так и NSPersistentContainer (если всё-таки Core), как сильно упрощающие жизнь в простых же сценариях.
По Вашему запросу:
Это нужно тестировать отдельно и явно обрабатывать в коде. В комментариях к статье хотелось бы услышать вашу версию обработки такой ситуации.
Это от бизнес-требований и критичности происходящего:
1) банковские приложения при протухании токена вовсе не дадут операцию "протыкать", ибо тебя уже выкинуло на экран авторизации;
2) я б UX-ово предпочёл явное а-ля "для операции (еёКороткоеОписание) необходимо авторизоваться" для первой попавшейся из очереди, а в последующих протухших также сразу обновить токен после успешной ре-авторизации
Спасибо за статью эту и предыдущие! Мне очень нравится Ваш слог, пожалуйста, продолжайте :)Особенно нравится стиль перехода к выводам почти в каждом абзаце и, главное, их меткость.
Вот за это прям низкий поклон. А то меня тут уже нейросетью пару раз обозвали. Слог из "прошлой" жизни остался, как и структурирование текстов - юрист я по первому образованию. И опыт написания неимоверного объема документов из прошлого сказывается - пишу легко и быстро, мыли на бумагу удобно ложатся. Ну и выводы в каждом разделе оттуда же.
1) Оставить один стиль, не смешивая GCD и async-await: в дальнейшем в статье последний используется;
Согласен, кода надергал из разных проектов, потому и каша (не уследил). Стараюсь в статье подчеркивать, что это всего лишь примеры, но чаще забываю.
2) Не в init'е стартовать, а отдельными методами рулить старт/стоп
Ну а почему бы и да? Хороший пример, соглашусь.
3) Некритично: предлагаю упомянуть как SwiftData, так и NSPersistentContainer (если всё-таки Core), как сильно упрощающие жизнь в простых же сценариях.
чуть позже добавлю, спасибо
1) банковские приложения при протухании токена вовсе не дадут операцию "протыкать", ибо тебя уже выкинуло на экран авторизации;
2) я б UX-ово предпочёл явное а-ля "для операции (еёКороткоеОписание) необходимо авторизоваться" для первой попавшейся из очереди, а в последующих протухших также сразу обновить токен после успешной ре-авторизации
Тут можно подискутировать немного. Я сам разработчик банковского приложения (и сейчас, и ранее).
У нас сейчас два подхода к обновлению токенов:
протухший — сразу переводим пользователя на авторизацию. Тут нет вариантов что-то протыкать, юзер неизбежно должен авторизоваться снова. Ну и еще нужно не забывать, что у банковских приложение есть запросы на сервер вне авторизованного контекста - информация о продуктах (не персонифицированная), адреса, контакты и много другого. Я это к тому, что не всегда пользователя перекидывает на авторизую. Но это, опять же, редкие случаи (разработчикам проще написать общую логику "протухания" токенов, не учитывая контекст).
протухший — не трогаем юзера до момента отправки первого запроса на сервер. То есть у юзера есть возможность пройти заполнение анкеты до последнего шага и закэшировать результат его действий по вводу данных (разработчики чаще таким не заморачиваются).
В ответ на первое утверждение могу сказать, что банковские приложения разные: некоторые могут и дать юзеру возможность попользоваться функциональностью без перекидывания на экран авторизации. Ну а после авторизации можно же вернуть юзера обратно — на то место, где он остановился.
Ну а на второе утверждение — да, принято, хороший вариант.
Спасибо за ваши предложения и комментарий. Думаю, многим будет полезно.
Нет соединения — не значит нет UX. Как не потерять доверие пользователя вместе с интернетом