3lvis / DATASource

Core Data's NSFetchedResultsController wrapper for UITableView and UICollectionView
Other
106 stars 27 forks source link

Multiple dataSource and one tableView. SearchController #71

Closed amanbolat closed 7 years ago

amanbolat commented 8 years ago

I have UIViewController with one UITableView and 3 lazy instances of dataSource and one optional that indicates activeDataSource for my tableView. Each dataSource has own predicate, sortDescriptor. I also added UISegmentedControl with 3 segments for each data source and function that will change activeDataSource and reload data. Every time viewDidLoad() i have function, that fetches data from server and sync it with Core Data and it can take 3-4 seconds. This 3-4 seconds i try randomly tap segmentedControl to change my dataSource and i get error:

Assertion failure in -[UITableView _endCellAnimationsWithContext:], /BuildRoot/Library/Caches/com.apple.xbs/Sources/UIKit/UIKit-3512.60.7/UITableView.m:1502
2016-05-19 09:43:19.702 MyApp[9301:2958707] CoreData: error: Serious application error.  An exception was caught from the delegate of NSFetchedResultsController during a call to -controllerDidChangeContent:.  attempt to insert row 0 into section 0, but there are only 0 rows in section 0 after the update with userInfo (null)

Yes, i can disable UserInteraction on segmentedControl, but sometimes user doesn't like wait for sync completion and just filter data, that he/she wants. In addition i want implement searchController, that will need 4th dataSource, and it will filter data more faster.

Any idea, how avoid this error?

3lvis commented 8 years ago

Hi Amanbolat,

Interesting problem. I believe the error is happening because new animations are starting while other ones are in progress. Combining multiple data sources in one table view has given me a lot of headaches in the past, I think we could figure out some workarounds if we manage to reproduce the error in a sample project, but have you considered using 3 table views each one with a different data source and just switch between them when the segmented control changes his value? Might make things much faster.

amanbolat commented 8 years ago

I will try your method with multiple table views and also will create sample project to reproduce the error.

amanbolat commented 8 years ago

@3lvis I found problem. Because i have only one tableView and multiple dataSources, each time i change dataSource for my tableView, previous dataSource doesn't stop call functions of it's NSFetchedResultsControllerDelegate functions: controllerWillChangeContent controllerDidChangeContent If i'm right all these methods still use tableView and cause problem. So i added new var isUpdatingTableView = true and this method, that i call when user changes segment of segmentedControl:

func segmentValueChanged(segmentedControl: UISegmentedControl) {
    if segmentedControl.selectedSegmentIndex == 0 {
      dataSourceONE.isUpdatingTableView = true
      dataSourceTWO.isUpdatingTableView = false
      dataSourceTHREE.isUpdatingTableView = false
      self.tableView.dataSource = dataSourceONE
      self.activeFRCSource = dataSourceONE

    } else if segmentedControl.selectedSegmentIndex == 1 {
      dataSourceTWO.isUpdatingTableView = true
      dataSourceONE.isUpdatingTableView = false
      dataSourceTHREE.isUpdatingTableView = false
      self.tableView.dataSource = dataSourceTWO
      self.activeFRCSource = dataSourceTWO

    } else if segmentedControl.selectedSegmentIndex == 2 {
      dataSourceTHREE.isUpdatingTableView = true
      dataSourceTWO.isUpdatingTableView = false
      dataSourceONE.isUpdatingTableView = false
      self.tableView.dataSource = dataSourceTHREE
      self.activeFRCSource = dataSourceTHREE
    }
    self.tableView.reloadData()
}

I think u can add feature it to your DATASource if somebody faced same problem.

3lvis commented 8 years ago

Hi @amanbolat,

Before I had something like what you're showing here, but it ended up introducing more problems than solutions. I'm happy that you got to fix your issue, I still think having multiple-controllers and datasources, or even just updating the predicate when switching datasources could be a better solution.

https://github.com/3lvis/DATASource/blob/master/Source/DATASource.swift#L84-L102

Let me know if I can help with anything else.

Best,

3lvis commented 8 years ago

Something like this could help too

http://stackoverflow.com/a/28878191/717416

amanbolat commented 8 years ago

Thanks, it's good idea. I'll try it too.

3lvis commented 8 years ago

@amanbolat Is there a chance you could share a sample project reproducing this issue? Would be nice to get it fixed in case is affecting other users too.

amanbolat commented 8 years ago

@3lvis https://github.com/amanbolat/DATASourceMultipleSourceSample On viewDidLoad it will fetch data and save to core data, then u can delete and fetch again, until u delete go to another segment fetch again and go back to first segment.

But i don't use your DATAStack, because i'm not so good at Core Data and have my own stack.

EDIT: I added Delete button to reproduce issue, because in my app i use our company ERP API where data is edited, deleted, added every minute and user need to be synced.

3lvis commented 8 years ago

@amanbolat thanks a lot! This is very useful.

3lvis commented 7 years ago

Doing some spring cleaning, please make a new issue if you still want to do this.