Rxswift: "DataSource not set" error

Created on 14 Nov 2016  Â·  6Comments  Â·  Source: ReactiveX/RxSwift

Short description of the issue:

I wrote a tableview like the example, but it report error "DataSource not set" , which I don't know where is wrong.

Expected outcome:

my app does not crash

What actually happens:

app crash

Self contained code example that reproduces the issue:

  //
//  WHSelectRegionController.swift
//  WormHole
//
//  Created by mac on 16/11/14.
//  Copyright © 2016年. All rights reserved.
//

import UIKit
import RxSwift
import RxCocoa
import RxDataSources

struct RegionModel {
    var name = "中国"
    var code = "86"
    var region = "CN"
}

class SelectRegionViewModel: NSObject {
    func getRegions() -> Observable<[SectionModel<String,RegionModel>]> {
        let regionModel1 = RegionModel()
        let regionModel2 = RegionModel()

        let regions = [regionModel1, regionModel2]
        let regions1 = [regionModel1, regionModel2]
        return Observable.just([SectionModel(model: "11", items: regions),SectionModel(model: "22", items: regions1)])
    }
}

class WHSelectRegionController: UIViewController {


    let datasources = RxTableViewSectionedReloadDataSource<SectionModel<String, RegionModel>>()
    let reuseId = "\(UITableViewCell.self)"
    let viewModel = SelectRegionViewModel()
    @IBOutlet weak var mainTable: UITableView!
    override func viewDidLoad() {
        super.viewDidLoad()
        title = "SelectRegion"

        view.addSubview(mainTable)
        mainTable.registerClass(UITableViewCell.self, forCellReuseIdentifier: reuseId)

        let datasource = self.datasources
        datasource.configureCell = {[weak self] aa,table,indexpath,region in
            guard let wself = self, let cell = wself.mainTable.dequeueReusableCellWithIdentifier(wself.reuseId) else{
                return UITableViewCell()
            }
            cell.textLabel?.text = region.name
            return cell
        }

        viewModel.getRegions()
            .bindTo(mainTable.rx_itemsWithDataSource(datasource))
            .addDisposableTo(DisposeBag())

    }



}


// If we can't get a self contained code example that reproduces the issue, there is a big chance we won't be able
// to help you because there is not much we can do.
//
// `Self contained code example` means:
//
// * that we should be able to just run the provided code without changing it.
// * that it will reproduce the issue upon running

RxSwift/RxCocoa/RxBlocking/RxTest version/commit

  • RxCocoa (2.6.0):

    • RxSwift (~> 2.5)

  • RxDataSources (0.9):

    • RxCocoa (~> 2.2)

    • RxSwift (~> 2.2)

  • RxSwift (2.6.0)

Platform/Environment

  • [x] iOS

How easy is to reproduce? (chances of successful reproduce after running the self contained code)

  • [x] easy, 100% repro

Xcode version:

  Version 7.3 (7D175)

:warning: Fields below are optional for general issues or in case those questions aren't related to your issue, but filling them out will increase the chances of getting your issue resolved. :warning:

Installation method:

  • [x] CocoaPods

I have multiple versions of Xcode installed:
(so we can know if this is a potential cause of your issue)

  • [x] no

Level of RxSwift knowledge:
(this is so we can understand your level of knowledge
and formulate the response in an appropriate manner)

  • [x] I have a small code base

Most helpful comment

Because DisposeBag will dispose all subscriptions it contains once it's being deallocated.

The wanted behavior is that the binding lasts until view controller deallocates.

This means

 viewModel.getRegions()
            .bindTo(mainTable.rx_itemsWithDataSource(datasource))
            .addDisposableTo(DisposeBag())

bind and then immediately unbind (because dispose bag) deallocates.

All 6 comments

Hi @a83988029 ,

Fix for this is in rxswift-2.0 branch.

I'll try to publish it soon since I see there is still a lot of people using 2.x version.

Hi @a83988029 ,

I think I might have confused your issue with one other old issue we had.

I believe that the problem is your case is that you've used dispose bag in a wrong way.

It should be

class WHSelectRegionController: UIViewController {
    let disposeBag = DisposeBag()

   override func viewDidLoad() {

      viewModel.getRegions()
            .bindTo(mainTable.rx_itemsWithDataSource(datasource))
            .addDisposableTo(disposeBag)
  }
}

Why do I have to assign DisposeBag() to a let, then use it?

Because DisposeBag will dispose all subscriptions it contains once it's being deallocated.

The wanted behavior is that the binding lasts until view controller deallocates.

This means

 viewModel.getRegions()
            .bindTo(mainTable.rx_itemsWithDataSource(datasource))
            .addDisposableTo(DisposeBag())

bind and then immediately unbind (because dispose bag) deallocates.

get it. thankyou!

I've made 2.6.1 release that improves this behavior and does crash the app, but using dispose bag in this way still isn't useful.

Was this page helpful?
0 / 5 - 0 ratings