Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Maybe delegate was already set in xib or storyboard and now it's being overwritten in code. #675

Closed
wangmengling opened this issue May 11, 2016 · 20 comments

Comments

@wangmengling
Copy link

ShareTableViewController: 0x7feda58d6330>)for object -><UITableView: 0x7feda5136000; frame = (0 0; 375 667); clipsToBounds = YES; autoresize = W+H; gestureRecognizers = <NSArray: 0x7feda5a0a790>; layer = <CALayer: 0x7feda5a007e0>; contentOffset: {0, 0}; contentSize: {375, 307}>. Maybe delegate was already set inxiborstoryboard` and now it's being overwritten in code.: file /Users/apple/Documents/luoye/lawyeruser/newLuoye/Pods/RxCocoa/RxCocoa/Common/DelegateProxyType.swift, line 199

@alexandremorgado
Copy link

Same problem here after upgrades to Cocoapods 1.0.0 and Xcode 7.3.1.

@sergdort
Copy link
Contributor

Hi, guys!

I don't think it a problem of Cocoapods

Most likely you are using bindTo(tableView. rx_itemsWithCellIdentifier) or methods from that family

What it does is trying to create data source and subscribe to subscribeProxyDataSourceForObject

You just need to remove it from xib or tableView.dataSource = nil before calling bindTo or use rx_setDataSource

@alexandremorgado
Copy link

@sergdort, you're right. It works setting datasource and delegate with nil in my viewDidLoad! But I still don't understand why this problem start occurring just after mentioned upgrades...

Thanks!

@kzaher
Copy link
Member

kzaher commented May 11, 2016

Hi guys,

This is an assert that fires when you have a previous data source set to warn you that you might be breaking that originally set data source.

assert(proxy.forwardToDelegate() === nil, "There is already a delegate set -> `\(proxy.forwardToDelegate()!)` for object -> `\(object)`.\nMaybe delegate was already set in `xib` or `storyboard` and now it's being overwritten in code.")

I'm kind of confused how to resolve this issue? This behavior is by design.

@sergdort
Copy link
Contributor

Hi, @kzaher . It seems to me that a lot of people don't understand what is the problem within assert message . I saw some people asked the same question in the slack channel.

May be we could somehow improve the message so it would be, more understandable. To kind of explaine why this a problem, because as far as I remember even if you creat UITableviewController manually, the dataSource and delegate set to the instance of controller, so it not only xib or storyboard.

@kzaher
Copy link
Member

kzaher commented May 11, 2016

How about this?

assert(proxy.forwardToDelegate() === nil, "This is a feature to warn you that there is already a delegate (or data source) set somewhere previously. The action you are trying to perform will clear that delegate (data source) and that means that some of your features that depend on that delegate (data source) being set will likely stop working.\nIf you are ok with this, try to set delegate (data source) to nil in front of this operation.\n This is the source object value: \(object)\n This this the original delegate (data source) value: \(proxy.forwardToDelegate()!)\nMaybe delegate was already set in xib or storyboard and now it's being overwritten in code.\n")

kzaher added a commit that referenced this issue May 15, 2016
@kzaher
Copy link
Member

kzaher commented May 15, 2016

This is just released. I think we can close it now.

@kzaher kzaher closed this as completed May 15, 2016
icanzilb added a commit to icanzilb/RxSwift that referenced this issue May 23, 2016
# By Krunoslav Zaher (23) and others
# Via Krunoslav Zaher
* 'master' of https://github.com/ReactiveX/RxSwift: (72 commits)
  Improves unit tests.
  Updates RxDataSources.
  Changes 2.5 to 2.5.0.
  Adds 2.5.0 changes to CHANGELOG.
  Makes `NSTextField` implement `RxTextInput`.
  Fixes Wikipedia automation tests.
  Improves delegate proxy messaging. ReactiveX#675
  Turns off bitcode for RxTests. ReactiveX#584
  Release 2.5
  More comprensible `ActivityIndicator`
  Improve language in comment
  Use new Swift selector syntax in comment
  Update comment to use new non-deprecated method
  Fix argument key in comment
  Typo in comment 'extensions' with an 's'
  Improves documentation for `DelegateProxy.observe`. ReactiveX#654
  Adds unit test for only setting different text values.
  Provides explanations for check.
  Fixes problems with two way binding that was caused by `rx_text` and always setting the text value even when the value was equal, and thus clearing the marked text state. ReactiveX#649
  Add missing Next link
  ...
@Bashta
Copy link

Bashta commented Dec 27, 2016

What if i still need access to tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat but i have set the delegate to nil so the delegate func its not being called.

@kzaher
Copy link
Member

kzaher commented Dec 27, 2016

@Bashta you would just use rx.setDelegate:

tableView.delegate = nil
tableView.rx.setDelegate(yourDelegate).addDisposableTo(disposeBag)

@BalaKarunakaran
Copy link

BalaKarunakaran commented May 9, 2017

Am using latest version of rxSwift and rxDataSource ... I too face the same problem ... And I use tableView.dataSource = nil and tableView.dataSource = nil before bindTo or use rx_setDataSource. Anybody help me to fix this.

@ZZHHAANNGG
Copy link

ZZHHAANNGG commented Aug 8, 2018

I have a similar issue, the TableView has no data source before binging.

ViewModel Code is here

Assertion failed: This is a feature to warn you that there is already a delegate (or data source) set somewhere previously. The action you are trying to perform will clear that delegate (data source) and that means that some of your features that depend on that delegate (data source) being set will likely stop working.
If you are ok with this, try to set delegate (data source) to nil in front of this operation.
This is the source object value: <UITableView: 0x7fdde9886e00; frame = (0 199; 414 537); clip

    override func viewDidLoad() {
        super.viewDidLoad()
        
        self.tableView.tableFooterView = UIView(frame: CGRect.zero)
        
        self.startDatePickerView = UIDatePicker(frame: CGRect(x: 0, y: 0, width: self.view.frame.size.width, height: 216))
        self.startDatePickerView.datePickerMode = .date
        self.startDatePickerView.date = Calendar.current.date(byAdding: .month, value: -1, to: Date()) ?? Date()
        
        self.endDatePickerView = UIDatePicker(frame: CGRect(x: 0, y: 0, width: self.view.frame.size.width, height: 216))
        self.endDatePickerView.datePickerMode = .date
        
        self.startDateTextField.inputView = startDatePickerView
        self.endDateTextField.inputView = endDatePickerView
    
        self.viewModel = CustomerViewModel()
        
        (self.startDateTextField.rx.text <-> self.viewModel.startDateTime).disposed(by: rx.disposeBag)
        (self.endDateTextField.rx.text <-> self.viewModel.endDateTime).disposed(by: rx.disposeBag)
        
        self.viewModel.list.subscribe(onNext:{ [unowned self](event) in
            switch event {
            case .success(let response):
                
                response.drive(self.tableView.rx.items(cellIdentifier: "customerCell", cellType: UITableViewCell.self))
                    {data source) to `nil` in front of this operation.
                        (index, customer, cell) in
                        cell.textLabel?.text = "\(customer.UserName ?? "")\t\t\(customer.CreateTime ?? "")"
                    }
                    .disposed(by: self.rx.disposeBag)
            case .failure(let error):
                print( error )
            }

        }).disposed(by: rx.disposeBag)

    
        
        
        self.startDatePickerView.rx.date.map{ [weak self](date) in
            return self?.viewModel.dateFormater.string(from: date)
        }.bind(to: self.startDateTextField.rx.text).disposed(by: rx.disposeBag)
        
        self.endDatePickerView.rx.date.map{ [weak self](date) in
            return self?.viewModel.dateFormater.string(from: date)
            }.bind(to: self.endDateTextField.rx.text).disposed(by: rx.disposeBag)
    }
}

@freak4pc
Copy link
Member

freak4pc commented Aug 8, 2018

@ZZHHAANNGG Make sure the Table View doesn't have a delegate as well, not just a datasource attached.

@ZZHHAANNGG
Copy link

@freak4pc I am sure the TableView has no delegate and datasouce. I changed the unowned self to weak self and the cell will not be created, the table is blank and has no such assertion issue.

@ivolnov
Copy link

ivolnov commented Aug 29, 2018

Got to be some weird storyboard magic or UITableViewController defaults - using itself as a datasource and a delegate...

@dylan
Copy link

dylan commented Oct 4, 2018

I've ran into this same issue, I too believe it's a storyboard thing. I've just set tableView.dataSource = nil and moved on.

@ivolnov
Copy link

ivolnov commented Oct 5, 2018

As far as I understand you can just use a raw UIViewController or etc and dragndrop a tableview into it, which is different from using a UITableViewController which conveniently implements delegates and binds itself to the table for free. In the latter case you will need to explicitly set delegates to nil before using the Rx fun...

@freak4pc
Copy link
Member

freak4pc commented Oct 5, 2018

UITableViewController takes over the dataSource in a way that can't be disconnected (AFAIK) via Storyboard - so in that case you'll need to manually set the dataSource to nil. Option 2 which is what I do, is just use a UITableView in a UIViewController - much finer control.

@marcopax
Copy link

marcopax commented Nov 13, 2018

I had a similar crash. Long story short: I resolved performing the cleaning before setting the delegate.

collectionView.dataSource = nil
collectionView.delegate = nil

collectionView.rx
    .setDelegate(self)
    .disposed(by: disposeBag)

Or in a do block before binding:

myDriver
.do {
    self.tableView.dataSource = nil
    self.tableView.delegate = nil
}
.drive(tableView.rx.items(dataSource: self.dataSource))
.disposed(by: disposeBag)

Hope this little hint can help someone.

AlanCasasArevalo added a commit to AlanCasasArevalo/TMDb that referenced this issue Mar 13, 2019
- Search navigator was implemented
- Detail navigator was implemented
- FIX into featured view controller
- FIX results view controller needs to put datasource to nil to work correctly. (ReactiveX/RxSwift#675)
@Ualikhan07
Copy link

@Bashta you would just use rx.setDelegate:

tableView.delegate = nil
tableView.rx.setDelegate(yourDelegate).addDisposableTo(disposeBag)

which delegate u set? i add programmatically tableView and now i can't set delegate...

@Bashta
Copy link

Bashta commented May 29, 2019

@Bashta you would just use rx.setDelegate:

tableView.delegate = nil
tableView.rx.setDelegate(yourDelegate).addDisposableTo(disposeBag)

which delegate u set? i add programmatically tableView and now i can't set delegate...

Thanks, man but the question was from Dec 27, 2016 XD

@ReactiveX ReactiveX locked as resolved and limited conversation to collaborators May 29, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests