代码之家  ›  专栏  ›  技术社区  ›  xxtesaxx

iOS Moya Web服务:拨打一个呼叫,等待所有其他呼叫完成,然后阻止新呼叫

  •  1
  • xxtesaxx  · 技术社区  · 6 年前

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

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

    现在,当用户更改密码时,可能会出现远程通知并导致另一个web服务调用。根据服务器负载和系统处理不同线程的方式,理论上可能会在另一个调用检索新令牌之前进行调用,但在服务器已使旧令牌无效之后进行调用。结果是出现HTTP 401未加密错误。

    我想防止这种情况发生,但我不确定最好的方法是什么,或者我的概念中是否有一些错误的想法。

    我找到了这个关于锁、互斥和信号量的页面: https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/Multithreading/ThreadSafety/ThreadSafety.html

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

    • 更改密码调用是“编写器”
    • 所有其他电话都是“读者”
    • 当用户或远程通知调用重新加载数据时,读卡器计数在锁上递增
    • 当用户更改密码时,锁上的写入程序计数将增加,新的读卡器将被阻止启动
    • 更改密码调用将等待所有其他“读取”调用完成
    • change password调用更改密码,更新令牌,最后减少锁并释放锁
    • 暂停的读卡器现在可以继续运行并开始增加读卡器计数并重新加载数据。

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

    1 回复  |  直到 6 年前
        1
  •  3
  •   iWheelBuy    6 年前

    我想分享一些关于中内置机制的想法 RxSwift公司 . 我认为有一些方法可以达到预期的行为。

    下面的代码只是一个理论,尚未经过测试。求你了,不要 cmd+c cmd+v此代码。其目的是显示简化版本 潜在解决方案。

    假设我们有:

    var activityIndicator = ActivityIndicator()
    var relayToken = BehaviorRelay<String?>(value: nil)
    

    哪里 ActivityIndicator this struct 这有助于捕捉多个 Observables .

    理论上,请求方法将如下所示:

    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 -将带有令牌的初始参数转换为完整请求参数的闭包。

    response: @escaping (P) -> Observable<R> -将完整参数转换为适当请求的闭包 Observable . 这是一个 莫亚 或者使用其他机制。

    此函数等待单个有效令牌信号,当接收到正确的令牌时,它将其转换为响应 可观察到 ,也由 activityIndicator . 这种跟踪需要知道所有“读取”调用何时完成。

    因此,将跟踪每个请求活动,并且只有在收到有效令牌时才启动任何请求。

    第二个重要事项-仅在没有活动请求时更改令牌:

    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)
    }
    

    因此,每当您决定更改令牌时,都可以通过此函数应用其更改。它观察所有请求的活动,当它们全部完成时,将应用更改。

    希望有帮助,如果需要,可以提问。

    编辑1

    “PATCH changePassword”可能不是正常请求之一,并且其活动可能无法跟踪 活动指示器 .

    1. 设置 relayToken = nil 当您需要更改密码时(自此步骤起,所有未来的正常请求都将等待正确的令牌)
    2. 等待已启动的请求完成( 活动指示器 将再次提供帮助)
    3. 发送“PATCH changePassword”请求以更改密码/令牌
    4. 写入新令牌 relayToken = some
    5. 所有暂停的请求将获得一个新令牌并自动开始执行
    6. 需要时返回步骤1

    因此,只有在完成所有已启动的请求后,服务器才会使令牌无效。

    “我的解决方案”阻止以下位置的所有新请求:

    relayToken.asObservable().filterNil().take(1)
    

    这意味着,虽然token是 nil -等等。如果没有 -仅进行一次。