Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/ios/118.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ios 如何防止多次调用异步函数,但每次都要调用完成?_Ios_Swift_Rx Swift - Fatal编程技术网

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

Ios 如何防止多次调用异步函数,但每次都要调用完成?,ios,swift,rx-swift,Ios,Swift,Rx Swift,这是我目前使用的代码: typealias ResponseHandler = (SomeResponse?, Error?) -> Void class LoginService { private var authorizeTokenCompletions = [ResponseHandler]() func authorizeToken(withRefreshToken refreshToken: String, completion: @escaping Resp

这是我目前使用的代码:

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)
    }
}
上面的代码是什么意思

  • authorizeToken函数可以根据需要调用任意多次(例如20次)
  • 一次只能推送一个异步请求(post)
  • 调用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执行此操作

    PS:一旦有可能,我将奖励100英镑的奖金给帮助我的人;)

    回答

    是否可以使用RxSwift执行此操作

    这是不可能的,因为每次我们触发函数时,它都会被调度,我们无法访问来自其他线程的回调

    在创建竞争条件时,解决方法是在一个单例中填充一次数据,而不是多次调用该函数,而是使用该单例

    其他一些方法也可能有效,singleton只是一个例子

    竞态条件:竞态条件是当一系列操作的预期完成顺序变得不可预测,导致程序逻辑最终处于未定义状态时发生的情况

    是否可以使用RxSwift执行此操作

    是的,这是可能的

    最简单的解决方案:

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

    我认为这是不可能的,因为每次我们触发函数时,它都会被调度,我们无法访问来自其他线程的回调。为什么不将数据推送到单例而不是多次调用它呢?您当前的代码具有明显的竞争条件、不安全的多线程数组操作,并且不会阻止多次调用
    post
    ,但您可能知道所有这些。虽然可能有一种方法可以让rx swift实现您想要的功能,但您可以让您的完成处理程序数组更新线程安全,并使用调度信号量查看帖子是否已经运行。@Paulw11确切地说,我只是在回答中指出了这一点,但是,阻止帖子再次运行不是他不想做的吗?不,需求中的第二点是,任何时候都只有一个
    post
    实例运行。@Paulw11哦,我没有注意到,是的,你是对的。但是这将如何有助于通过第一次
    post
    结果进行回访,您可以添加一个答案吗?回访完成的顺序对我来说并不重要…因此这可能不是竞争条件。是的,但您正在尝试访问正在进行的任务,并根据第一次回访结果修改它们,我认为,即使使用信号灯,也不可能一次推一个帖子感谢you@Bartłomiejsemanńczyk Paulw11可以有另一个解决办法,但目前是的,我猜这可能就是它。
    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.
    }