Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/swift/16.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
Swift 缓冲区可观察,直到另一个可观察完成_Swift_Rx Swift_Reactivex - Fatal编程技术网

Swift 缓冲区可观察,直到另一个可观察完成

Swift 缓冲区可观察,直到另一个可观察完成,swift,rx-swift,reactivex,Swift,Rx Swift,Reactivex,我正在使用RxSwift包装移动应用程序的服务器同步过程。我有一个可观察的,它包装了一个websocket连接,并将收到的每条消息作为事件发出。类似地,我有一个可观察的,它封装了一个API同步过程。一旦我的应用程序打开WebSocket连接,服务器就会发送一条hello消息。收到该消息后,我希望启动同步进程并缓冲所有事件,直到同步完成。这就是我挣扎的地方。目前,我有: self.eventStreamService.observe(connection).scan((nil, [])) { (s

我正在使用RxSwift包装移动应用程序的服务器同步过程。我有一个
可观察的
,它包装了一个websocket连接,并将收到的每条消息作为
事件发出
。类似地,我有一个
可观察的
,它封装了一个API同步过程。一旦我的应用程序打开WebSocket连接,服务器就会发送一条
hello
消息。收到该消息后,我希望启动同步进程并缓冲所有事件,直到同步完成。这就是我挣扎的地方。目前,我有:

self.eventStreamService.observe(connection).scan((nil, [])) { (state, event) -> (Observable<RemoteEvent>?, [RemoteEvent]) in
  guard event.type == "hello" else {
    return (state.0?.concat(Observable.just(event)), state.1 + [event])
  }

  // This is the sync operation
  return (
    self.synchronizationService
      .synchronize(ConnectionSynchronizationContext(connection: connection), lightweight: true)
      .toArray()
      .flatMap { results -> Observable<RemoteEvent> in
        (state.1 + [event]).toObservable()
      },
    []
  )
}
.flatMapLatest { $0.0 ?? Observable.empty() }
self.eventStreamService.observe(connection).scan((nil,[]){(state,event)->(Observable?,[RemoteEvent])中的
guard event.type==“hello”else{
返回(state.0?.concat(Observable.just(event)),state.1+[event])
}
//这是同步操作
返回(
自动同步服务
.synchronize(ConnectionSynchronizationContext(连接:连接),轻量级:true)
.toArray()
.flatMap{results->在
(state.1+[event]).toObservable()
},
[]
)
}
.flatMapLatest{$0.0??可观察的.empty()}

尽管这相当难看,但它也有一个明显的缺陷:任何传入的事件都会导致重新订阅同步
可观察的
,然后重新启动整个同步过程。我相信一定有更好的方法可以做到这一点。

以下是您如何获得所需功能的方法:

// this is a stub for the purpose of the example
let interval = Observable<Int>.interval(1, scheduler: MainScheduler.instance)
let websocketEvents = interval
    .map { i -> String in
        if i == 1 {
            return "hello"
        } else {
            return String(i)
        }
    }
    .replayAll()

websocketEvents.connect()

func performSync() -> Observable<Void> {
    return Observable<Void>.create { o in
        print("starting sync")
        // actually start sync with server
        // ....
        delay(2.0) {
            print("sync finished")
            o.onNext(())
        }
        return NopDisposable.instance
    }
}

// websocket events as they come, regardless of sync status
websocketEvents
    .subscribeNext { e in
        print("websocket event received: \(e)")
    }

// all websocket events, buffered and only emitted post-sync
websocketEvents
    .filter { $0 == "hello" }
    .flatMapLatest { _ in performSync() }
    .flatMapLatest { _ in websocketEvents }
    .subscribeNext { e in
        print("websocket event post sync: \(e)")
    }
//这是本示例中的存根
让interval=Observable.interval(1,调度器:MainScheduler.instance)
让websocketEvents=间隔
.map{i->输入字符串
如果i==1{
回复“你好”
}否则{
返回字符串(i)
}
}
.replayAll()
websocketEvents.connect()
func performSync()->可观察{
返回可观察的。在中创建{o
打印(“开始同步”)
//实际启动与服务器的同步
// ....
延迟(2.0){
打印(“同步完成”)
o、 onNext(())
}
return.instance
}
}
//websocket事件发生时,不管同步状态如何
websocketEvents
.subscribeNext{e in
打印(“接收到websocket事件:\(e)”)
}
//所有websocket事件,缓冲且仅在同步后发出
websocketEvents
.filter{$0==“hello”}
.flatMapLatest{inPerformSync()}
.flatMapLatest{inWebSocketEvents}
.subscribeNext{e in
打印(“websocket事件后期同步:\(e)”)
}
这将输出:

接收到websocket事件:0
收到websocket事件:您好
开始同步
接收到websocket事件:2
接收到websocket事件:3
同步完成
websocket事件后期同步:0
websocket事件后期同步:您好
websocket事件后期同步:2
websocket事件后期同步:3
接收到websocket事件:4
websocket事件后期同步:4
接收到websocket事件:5
websocket事件后期同步:5


“hello”是websocket发出的第一个事件吗?如果不是,是否应该缓冲“hello”之前的任何事件,还是应该缓冲“hello”/sync start之后的任何事件?这个用例看起来很奇怪,但我将忽略它,从表面上看,因为我假设您已将问题更改为实际用例的简单版本。@solidcell可以安全地假设
hello
将是第一个事件。在此之前的任何事情(实际上都没有)都可以忽略。您是对的,这既是一个奇怪的用例,也是问题的简化版本。但最终,对于我拥有的应用程序,这是防止争用条件的最简单方法(例如,如果同步发生,然后websocket连接,则可能会错过事件;如果websocket连接并同步时没有缓冲区,则可以在支持数据可用之前处理事件)。在解决其他问题之前,此解决方案大多是临时性的。如何可能出现这种情况?:“如果同步发生,然后websocket连接”。如果websocket需要连接才能发送“hello”消息,以便我们尝试启动同步,那么在连接websocket之前,同步怎么可能发生?对不起,我刚才解释了为什么我现在要这样做。websocket发送hello是正确的,之后会进行同步。我在建议为什么我现在没有设置同步,在连接之前进行同步。这太棒了!一个问题-我是否正确地假设
Replayal
将继续保留流中发出的所有项目,即使它们已被回放?这里有关于内存使用的问题吗?我目前的方法(非常粗糙和不完善)确实对缓冲区施加了最大大小限制,如果它不能在缓冲x个条目之前完成同步(为了简洁起见,问题中没有列出),则会出错。是的,这绝对是值得关注的。有
replay(bufferCount:Int)
可以限制缓冲区大小。但是,如果可能的话,你应该考虑一个不同的方法来同步你的同步元素,而不是缓冲元素。谢谢你的澄清。至于同步,我已经尝试了几种不同的方法。我最喜欢的一个是服务器在最后一个x持续时间内保留事件缓存。然后在连接时,它只会转储您错过的所有内容,因此客户端无需做额外的工作。问题在于(取决于应用程序和事件类型),这可能会导致比进行API调用多得多的数据使用。