RXSwift collectionView不';调用.onNext(newArray)时无法更新

RXSwift collectionView不';调用.onNext(newArray)时无法更新,swift,uicollectionview,rx-swift,Swift,Uicollectionview,Rx Swift,我有个问题。我得到了一个绑定到winPinataActions PublishSubject()的collectionview。最初,当加载collectionview时,一切正常,它会按对象显示,但是当pull to refresh操作更改publishSubject数据时,UI不会更新,它仍然会获取publishSubject的旧内容。 下面是我如何绑定collectionView的: class WinPinatasViewController: UIViewController { @I

我有个问题。我得到了一个绑定到winPinataActions PublishSubject()的collectionview。最初,当加载collectionview时,一切正常,它会按对象显示,但是当pull to refresh操作更改publishSubject数据时,UI不会更新,它仍然会获取publishSubject的旧内容。 下面是我如何绑定collectionView的:

class WinPinatasViewController: UIViewController {
@IBOutlet weak var collectionView: UICollectionView!
private let bag = DisposeBag()

 override func viewDidLoad() {
        super.viewDidLoad()
        configureCollectionView()
    }

func configureCollectionView() {
     /..../
     viewModel.winPinataActions
            .observeOn(MainScheduler.instance)
            .bind(to: collectionView.rx.items(cellIdentifier: "winPinatasCell", cellType: WinPinatasCell.self)) {(row, item, cell) in
            cell.configureCell(with: item)
            
        }.disposed(by: bag)
     viewModel.getPinataActions()
     }    

@objc func handleRefreshControl() {
    viewModel.getPinataActions()
    DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
      self.collectionView.refreshControl?.endRefreshing()
   }
}
}
这是我的viewModel类:

class WinPinatasViewModel {
    
    let winPinataActions = PublishSubject<[WinPinatasAction]>()
    
    func getPinataActions() {
        guard let ssoId = UserDefaultsStore.ssoId() else {
            return
        }
        NetworkEngine.shared.gamificationNetwork.getUserWinPinataActions(subject: winPinataActions, ssoID: ssoId)
    }
}
类WinPinatasViewModel{
让winPinataActions=PublishSubject()
func getPinataActions(){
guard let ssoId=UserDefaultsStore.ssoId()else{
返回
}
NetworkEngine.shared.gamificationNetwork.getUserWinPinataActions(主题:winPinataActions,ssoID:ssoID)
}
}
以及我的NetworkEngine getuserPinataActions方法:

func getUserWinPinataActions(subject winPinatasActions: PublishSubject<[WinPinatasAction]>, ssoID: String) {
           //...//
           let actions = try decoder.decode([WinPinatasAction].self, from: jsonData)
           winPinatasActions.onNext(actions)
           winPinatasActions.onCompleted()
          //...//
}
func getUserWinPinataActions(主题WinPinataActions:PublishSubject,ssoID:String){
//...//
let actions=try decoder.decode([WinPinatasAction].self,from:jsonData)
winPinatasActions.onNext(操作)
winPinatasActions.onCompleted()
//...//
}

完成pull to refresh操作后,将调用handleRefreshControl()方法。此外,在调试过程中,我可以看到在pullToRefresh操作之后,新数据在我的NetworkEngine方法中被接收,并且.onNext()和onCompleted()都被调用。但是当我在collectionView中滚动数据时,单元格项来自旧数组,而不是新数组。你能帮我吗?我做错了什么?

这里的问题是,您正在向主题发送一个
已完成的
事件,但之后希望它能够发送其他事件。可观测合同规定,一旦可观测对象(或本例中的主体)发送了一个已完成的事件,在任何情况下都不会再发送任何事件

不要将主题传递到
getUserWinPinataActions
中,而应该从函数返回一个可观察的对象

这更接近您应该拥有的:

class WinPinatasViewController: UIViewController {
    @IBOutlet weak var collectionView: UICollectionView!
    private let bag = DisposeBag()
    let viewModel = WinPinatasViewModel()

    override func viewDidLoad() {
        super.viewDidLoad()

        collectionView.refreshControl!.rx.controlEvent(.valueChanged)
            .startWith(())
            .flatMapLatest { [viewModel] in
                viewModel.getPinataActions()
            }
            .observeOn(MainScheduler.instance)
            .bind(to: collectionView.rx.items(cellIdentifier: "winPinatasCell", cellType: WinPinatasCell.self)) {(row, item, cell) in
                cell.configureCell(with: item)

            }
            .disposed(by: bag)
    }
}

class WinPinatasViewModel {

    func getPinataActions() -> Observable<[WinPinatasAction]> {
        guard let ssoId = UserDefaultsStore.ssoId() else {
            return .empty()
        }
        return GamificationNetwork.shared.getUserWinPinataActions(ssoID: ssoId)
    }
}

class GamificationNetwork {
    static let shared = GamificationNetwork()

    func getUserWinPinataActions(ssoID: String) -> Observable<[WinPinatasAction]> {
        Observable.create { observer in
            let jsonData = Data() // get jsonData somehow
            let actions = try! decoder.decode([WinPinatasAction].self, from: jsonData)
            observer.onNext(actions)
            observer.onCompleted()
            return Disposables.create { /* cancelation code, if any */ }
        }
    }
}
类WinPinatasViewController:UIViewController{
@ibvar collectionView:UICollectionView!
私人出租包=处置包()
让viewModel=WinPinatasViewModel()
重写func viewDidLoad(){
super.viewDidLoad()
collectionView.refreshControl!.rx.controlEvent(.valueChanged)
.startWith(())
.flatmap中最新的{[viewModel]
viewModel.getPinataActions()
}
.observeOn(MainScheduler.instance)
.bind(到:collectionView.rx.items(cellIdentifier:“winPinatasCell”,cellType:winPinatasCell.self)){(行、项、单元格)中的
cell.configureCell(带:项)
}
.处置(由:袋)
}
}
类WinPinatasViewModel{
func getPinataActions()->可观察{
guard let ssoId=UserDefaultsStore.ssoId()else{
return.empty()
}
返回GamificationNetwork.shared.getUserWinPinataActions(ssoID:ssoID)
}
}
类游戏化网络{
静态let shared=GamificationNetwork()
func getUserWinPinataActions(ssoID:String)->可观察{
创建{observate in
让jsonData=Data()//以某种方式获取jsonData
让actions=try!decoder.decode([WinPinatasAction].self,from:jsonData)
observer.onNext(行动)
observer.onCompleted()
返回一次性物品。创建{/*取消代码,如果有*/}
}
}
}
记住:

受试者提供了一种方便的方式来浏览Rx,但不建议日常使用。。。在生产代码中,您可能会发现很少使用IObserver接口和主题类型。。。IObservable接口是主要的类型,您将接触到它来表示运动中的数据序列,因此它将成为您使用Rx进行大多数工作的核心关注点

--

如果你发现自己在寻找一个主题来解决一个问题,那么你很可能是做错了什么


另外,本文可能会有所帮助:

您是说在视图模型和网络引擎中都有一个
winPinatasActions
?尝试发布编译后的代码,我可能会有所帮助。@DanielT。是的,winPinatasActions是PublishSubject(),当网络调用GetUserWinPinatasActions(subject winPinatasActions:PublishSubject,ssoID:String)时,它作为参数发送,在网络调用中,在获取我的操作后,我使用winPinatasActions.onNext(操作)和winPinatasActions.onCompleted()发送它们。这些类相当大,这就是为什么我不发布整个类的原因。但是所有与我发布的collectionView、PublishSubject和网络电话相关的内容。不要发布整个课程。但是,如果您所做的工作至少能够在无需任何额外工作的情况下编译,这将有所帮助。请注意,我的答案中的代码也不是整个类,但它是编译的。