ios 如何防止多次调用异步函数,但每次都调用完成?

mbzjlibv  于 2023-03-05  发布在  iOS
关注(0)|答案(2)|浏览(262)

这是我目前正在使用的代码:

typealias ResponseHandler = (SomeResponse?, Error?) -> Void

class LoginService {
    private var authorizeTokenCompletions = [ResponseHandler]()
    func authorizeToken(withRefreshToken refreshToken: String, completion: @escaping ResponseHandler) {
        if authorizeTokenCompletions.isEmpty {
            authorizeTokenCompletions.append(completion)
            post { [weak self] response, error in
                self?.authorizeTokenCompletions.forEach { $0(response, error) }
                self?.authorizeTokenCompletions.removeAll()
            }
        } else {
            authorizeTokenCompletions.append(completion)
        }
    }

    private func post(completion: @escaping ResponseHandler) {
        // async
        completion(nil, nil)
    }
}

以上代码的思想是什么?

  1. authorizeToken函数可以根据需要调用多次(例如20次)
    1.一次只能推送一个异步请求(post)。
    1.调用authorizeToken函数的所有完成都应该使用与第一个完成的函数相同的参数。
    用法:
let service = LoginService()

service.authorizeToken(withRefreshToken: "") { a, b in print(a)}
service.authorizeToken(withRefreshToken: "") { a, b in print(a)}
service.authorizeToken(withRefreshToken: "") { a, b in print(a)}
service.authorizeToken(withRefreshToken: "") { a, b in print(a)}
service.authorizeToken(withRefreshToken: "") { a, b in print(a)}

以上所有完成的结果都应与调用的第一个结果一起打印。
RxSwift可以做到这一点吗?

vptzau2j

vptzau2j1#

RxSwift可以做到这一点吗?
是的,这是可能的。RxSwift and Handling Invalid Tokens.
最简单的解决方案:

func authorizeToken(withRefreshToken refreshToken: String) -> Observable<SomeResponse> {
    Observable.create { observer in
        DispatchQueue.main.asyncAfter(deadline: .now() + 3) {
            print("async operation")
            observer.onNext(SomeResponse())
        }
        return Disposables.create()
    }
}

let response = authorizeToken(withRefreshToken: "")
    .share(replay: 1)

response.subscribe(onNext: { print($0) })
response.subscribe(onNext: { print($0) })
response.subscribe(onNext: { print($0) })
response.subscribe(onNext: { print($0) })
response.subscribe(onNext: { print($0) })

以上方法只有在所有请求(subscribe s)都在第一个请求完成之前发出的情况下才有效,就像你的代码一样。
如果您希望存储响应以便在完成后使用,那么可以使用replay而不是share

let response = authorizeToken(withRefreshToken: "")
    .replayAll()

let disposable = response.connect() // this calls the async function. The result will be stored until `disposable.dispose()` is called.

response.subscribe(onNext: { print($0) })

DispatchQueue.main.asyncAfter(deadline: .now() + 5) {
    response.subscribe(onNext: { print($0) }) // this won't perform the async operation again even if the operation completed some time ago.
}
svgewumm

svgewumm2#

应答
是否可以使用RxSwift实现这一点
这是不可能的,因为每次我们触发函数时,它都会被调度,并且我们无法访问来自其他线程的回调。
您正在创建一个争用条件,一种解决方法是在一个单例中填充一次数据,而不是使用该单例多次调用函数。
一些其他方法也可以工作,单例只是一个示例。
竞态条件:争用条件是当操作序列的预期完成顺序变得不可预测时发生的情况,导致程序逻辑以未定义的状态结束

相关问题