Manejo de errores

Manejo de errores

Una vez que se genera un evento de error en la secuencia, se terminará toda la secuencia. RxSwift tiene dos mecanismos principales de manejo de errores:

reintentar-reintentar capturar-reanudar reintentar-reintentar

retry permite que la secuencia vuelva a intentar después de un error:

// Si falla la solicitud de JSON, vuelva a intentarlo de inmediato, // Si falla después de 3 intentos de reintento, se generará un error

let rxJson: Observable<JSON> = ...

rxJson
    .retry(3)
 .subscribe(onNext: { json in  print("取得 JSON 成功: \(json)")  }, onError: { error in  print("取得 JSON 失败: \(error)")  })  .disposed(by: disposeBag) 

El código anterior es un reintento muy directo (3), es decir, cuando se produce un error, se realiza la operación de reintento y el reintento se realiza como máximo 3 veces.

reintentarCuando

Si necesitamos intentarlo nuevamente después de un retraso cuando ocurre un error, se puede lograr de la siguiente manera:

// Cuando falla la solicitud de JSON, espere 5 segundos e intente nuevamente,

let retryDelay: Double = 5  // 重试延时 5 秒

rxJson
    .retryWhen { (rxError: Observable<Error>) -> Observable<Int> in
 return Observable.timer(retryDelay, scheduler: MainScheduler.instance)  }  .subscribe(...)  .disposed(by: disposeBag) 

Aquí necesitamos usar el operador retryWhen, que describe principalmente cuándo se debe volver a intentar, y controla el momento del reintento a través del Observable devuelto en el cierre:

.retryWhen { (rxError: Observable<Error>) -> Observable<Int> in
    ...
}

El parámetro en el cierre es Observable, que es la secuencia de errores generados, y el valor de retorno es Observable. Cuando el Observable devuelto emite un elemento, la operación se vuelve a intentar. Cuando emite un error o un evento completado, no volverá a intentarlo y pasará este evento al observador posterior.

Si necesita agregar un número máximo de reintentos:

// Si la solicitud de JSON falla, espere 5 segundos e intente nuevamente. // Después de 4 reintentos y aún falla, arroje un error

let maxRetryCount = 4       // 最多重试 4 次
let retryDelay: Double = 5  // 重试延时 5 秒

rxJson
 .retryWhen { (rxError: Observable<Error>) -> Observable<Int> in  return rxError.flatMapWithIndex { (error, index) -> Observable<Int> in  guard index < maxRetryCount else {  return Observable.error(error)  }  return Observable<Int>.timer(retryDelay, scheduler: MainScheduler.instance)  }  }  .subscribe(...)  .disposed(by: disposeBag) 

Lo que queremos lograr aquí es que si volvemos a intentarlo más de 4 veces, se generará un error. Si el error ocurre dentro de 4 veces, espere 5 segundos e intente nuevamente:

...
rxError.flatMapWithIndex { (error, index) -> Observable<Int> in
    guard index < maxRetryCount else {
        return Observable.error(error)
 }  return Observable<Int>.timer(retryDelay, scheduler: MainScheduler.instance) } ... 

Usamos el operador flatMapWithIndex porque puede proporcionarnos el número de índice incorrecto. Luego use este número de índice para determinar si se excede el número máximo de reintentos. Si lo excede, se genera un error. Si no se excede, espere 5 segundos e intente nuevamente.

catchError-recovery

catchError puede reemplazar un error con un elemento de repuesto o un conjunto de elementos de repuesto cuando se produce el error:

searchBar.rx.text.orEmpty
    ...
    .flatMapLatest { query -> Observable<[Repository]> in
        ...
 return searchGitHub(query)  .catchErrorJustReturn([])  }  ...  .bind(to: ...)  .disposed(by: disposeBag) 

Usamos catchErrorJustReturn en nuestra búsqueda inicial de Github. Cuando se produce un error, se devuelve una matriz vacía y se muestra una página de lista vacía.

También puede usar catchError. Cuando se produce un error, reemplace el evento de error con una secuencia alternativa:

// Obtenga primero los datos de la red, si la adquisición falla, obtenga los datos del caché local

let rxData: Observable<Data> = ...      // 网络请求的数据
let cahcedData: Observable<Data> = ...  // 之前本地缓存的数据

rxData
 .catchError { _ in cahcedData }  .subscribe(onNext: { date in  print("获取数据成功: \(date.count)")  })  .disposed(by: disposeBag) Result

Si solo queremos darle al usuario un mensaje de error, ¿cómo lo hacemos?

Lo siguiente proporciona una solución más directa, pero hay algunos problemas con esta solución:

// Cuando el usuario hace clic en el botón actualizar, // saca inmediatamente la información modificada del usuario. // Luego inicie una solicitud de red para realizar una operación de actualización, // Una vez que la operación falla, le pregunta al usuario el motivo del error

updateUserInfoButton.rx.tap
    .withLatestFrom(rxUserInfo)
    .flatMapLatest { userInfo -> Observable<Void> in
        return update(userInfo)
 }  .observeOn(MainScheduler.instance)  .subscribe(onNext: {  print("用户信息更新成功")  }, onError: { error in  print("用户信息更新失败: \(error.localizedDescription)")  })  .disposed(by: disposeBag) 

Esto es muy sencillo. Pero una vez que la operación de solicitud de red falla, la secuencia terminará. La suscripción completa será cancelada. Si el usuario vuelve a hacer clic en el botón de actualización, no puede iniciar una solicitud de red para actualizar nuevamente.

Para resolver este problema, debemos elegir una solución adecuada para el manejo de errores. Por ejemplo, use el resultado de enumeración que viene con el sistema:

public enum Result<Success, Failure> where Failure : Error {
    case success(Success)
    case failure(Failure)
}

Luego, el código anterior debe modificarse para:

updateUserInfoButton.rx.tap
    .withLatestFrom(rxUserInfo)
    .flatMapLatest { userInfo -> Observable<Result<Void, Error>> in
        return update(userInfo)
 .map(Result.success) // 转换成 Result  .catchError { error in Observable.just(Result.failure(error)) }  }  .observeOn(MainScheduler.instance)  .subscribe(onNext: { result in  switch result { // 处理 Result  case .success:  print("用户信息更新成功")  case .failure(let error):  print("用户信息更新失败: \(error.localizedDescription)")  }  })  .disposed(by: disposeBag) 

De esta manera, nuestro evento de error se envuelve en un elemento Result.failure (Error) y no se terminará toda la secuencia. Incluso si la solicitud de red falla, toda la suscripción aún existe. Si el usuario vuelve a hacer clic en el botón de actualización, puede iniciar una solicitud de red para realizar la operación de actualización.

Supongo que te gusta

Origin www.cnblogs.com/liuxiaokun/p/12684718.html
Recomendado
Clasificación