Обновить

Нет соединения — не значит нет UX. Как не потерять доверие пользователя вместе с интернетом

Уровень сложностиПростой
Время на прочтение8 мин
Охват и читатели5.5K
Всего голосов 3: ↑2 и ↓1+1
Комментарии6

Комментарии 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-ово предпочёл явное а-ля "для операции (еёКороткоеОписание) необходимо авторизоваться" для первой попавшейся из очереди, а в последующих протухших также сразу обновить токен после успешной ре-авторизации

Тут можно подискутировать немного. Я сам разработчик банковского приложения (и сейчас, и ранее).

У нас сейчас два подхода к обновлению токенов:

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

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

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

Ну а на второе утверждение — да, принято, хороший вариант.
Спасибо за ваши предложения и комментарий. Думаю, многим будет полезно.

Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации