ios - iOS Moya Web服务: make one call wait for all others to finish,然后阻止新调用

标签 ios multithreading web-services rx-swift moya

在我的应用程序中,我正在使用Moya和RxSwift进行Web服务调用。这些调用是异步的,可以在新数据可用时由用户交互以及远程通知触发。

每个Web服务调用都需要在其 header 中进行身份验证。当用户更改密码时,将通过更改密码Web服务调用重新生成并返回 token 。

现在,当用户更改密码时,可能会发生远程通知并导致另一个Web服务调用。根据服务器的负载以及系统处理不同线程的方式,理论上可能发生以下情况:该调用是在另一个调用检索到新 token 之前,而服务器已经使旧 token 无效之后进行的。结果是HTTP 401未授权错误。

我想避免这种情况,但是我不确定最好的方法是什么,或者我的想法有误。

我发现此页面讨论锁,互斥锁和信号灯:https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/Multithreading/ThreadSafety/ThreadSafety.html

似乎我应该这样使用“读写锁”:

  • 更改密码调用为“writer”
  • 所有其他调用均为“读者”
  • 当由用户或由于远程通知引起重新加载数据的调用时,锁
  • 上的读取器计数会增加
  • 当用户更改密码时,写者计数在锁上增加,并且新阅读器被阻止启动
  • 更改密码调用等待所有其他“读取”调用来完成
  • 更改密码调用更改密码,更新 token 并最终减少锁并将其释放
  • 现在,挂起的读取器可以继续运行,并开始增加读取器计数并重新加载数据。

  • 到目前为止,这是正确的吗?接下来的一个大问题是:是否有更好的方法?在我开始更改所有Web服务调用之前:Moya或RxSwift中是否有内置机制可用于此目的?

    最佳答案

    我想分享一些关于 RxSwift 中的内置机制的想法。我认为有一些方法可以实现所需的行为。

    The code below is just a theory and hasn't been tested. Please, don't cmd+c cmd+v this code. Its purpose is to show the simplified version of potential solution.



    可以说我们有:
    var activityIndicator = ActivityIndicator()
    var relayToken = BehaviorRelay<String?>(value: nil)
    

    其中ActivityIndicatorthis struct,这有助于捕获多个Observables的 Activity 。

    从理论上讲,请求方法将如下所示:
    func request<D, P, R>(data: D, parameters: @escaping (D, String) -> P, response: @escaping (P) -> Observable<R>) -> Observable<R> {
        return Observable
            .just(data)
            .flatMap({ (data: D) -> Observable<R> in
                return relayToken
                    .asObservable()
                    .filterNil()
                    .take(1)
                    .map({ parameters(data, $0) })
                    .flatMap({ (parameters: P) -> Observable<R> in
                        return activityIndicator.trackActivity(response(parameters))
                    })
            })
    }
    

    在哪里:
    data: D-初始请求参数
    parameters: @escaping (D, String) -> P-将带有 token 的初始参数转换为完整请求参数的闭包。
    response: @escaping (P) -> Observable<R>-将完整参数转换为正确请求Observable的闭包。这是使用 Moya 或其他某种机制的地方。

    此函数等待单个有效 token 信号,并在接收到正确的 token 时将其转换为响应Observable,也由activityIndicator跟踪。需要进行此类跟踪才能知道何时完成所有“读取”调用。

    结果-跟踪每个请求 Activity ,并且只有在收到有效 token 后,任何请求才会开始。

    第二件事-仅在没有 Activity 请求时更改 token :
    func update(token: String?) {
        _ = Observable
            .just(token)
            .flatMap({ (token: String?) -> Observable<String?> in
                return activityIndicator
                    .asObservable()
                    .filter({ $0 == false })
                    .take(1)
                    .map({ _ in token })
            })
            .bind(to: relayToken)
    }
    

    因此,无论何时决定更改 token ,都可以通过此功能应用其更改。它观察所有请求的 Activity ,并观察所有请求的 Activity -更改将被应用。

    希望对您有所帮助,如有需要,请提问。

    编辑1

    “PATCH changePassword”可能不是正常请求之一,并且其 Activity 可能无法通过activityIndicator进行跟踪。
  • 当您需要更改密码时(此步骤以后,所有以后的正常请求将要等待正确的 token ),请设置relayToken = nil
  • 等待已经开始的请求完成(activityIndicator将再次提供帮助)
  • 发送“PATCH changePassword”请求以更改密码/ token
  • 编写新 token relayToken = some
  • 所有暂停的请求将获得一个新 token 并自动开始执行
  • 需要时返回步骤1

  • 因此,服务器将仅在所有已经启动的请求完成后使 token 无效。

    我的解决方案阻止了以下所有新请求:
    relayToken.asObservable().filterNil().take(1)
    

    这意味着,虽然 token 是nil-等待。如果不是nil,则只能进行一次。

    关于ios - iOS Moya Web服务: make one call wait for all others to finish,然后阻止新调用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48218770/

    相关文章:

    ios - 如何使用文本字段处理 TableView 单元格

    iOS - 覆盖整个应用程序的 UIActivityIndi​​catorView 的默认颜色

    ios - 如何在按下 searchBar 时显示 UISearchController 的 searchResultsController

    c - 节目录制时间

    winforms - 为什么我在关闭 Windows 窗体应用程序后会收到错误消息?

    C# 枚举属性 null 与 0

    ios - 从画廊获取图像到我的应用程序时内存泄漏

    java - JAVA中使用Atomic和无限循环做同步

    java - 如何使用 Java 创建一个简单的 Web 应用程序来测试我的 Web 服务

    c# - 在用户选择文件后添加提示