Short description of the issue:
App crashes with "Datasource is not set" error in UICollectionViewController after it is de-initialized by popping to the previous viewController.
This happens with RxSwift 3.1.0 or above. It works fine with RxSwift 3.0.1
Expected outcome:
It does not crash after popping back to the previous viewController.
What actually happens:
it crashes with "Datasource is not set" error.
Solution:
nil at unexpected time and causing crashes. Error logs are below.2017-03-17 19:21:30.754 Atte[46311:344112] *** Assertion failure in -[UICollectionView _createPreparedSupplementaryViewForElementOfKind:atIndexPath:withLayoutAttributes:applyAttributes:], /SourceCache/UIKit_Sim/UIKit-3347.44.2/UICollectionView.m:1400
2017-03-17 19:21:30.776 Atte[46311:344112] *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'UICollectionView dataSource is not set'
*** First throw call stack:
(
0 CoreFoundation 0x043a2746 __exceptionPreprocess + 182
1 libobjc.A.dylib 0x0386ca97 objc_exception_throw + 44
2 CoreFoundation 0x043a25da +[NSException raise:format:arguments:] + 138
3 Foundation 0x034d9720 -[NSAssertionHandler handleFailureInMethod:object:file:lineNumber:description:] + 118
4 UIKit 0x05a8e06d -[UICollectionView _createPreparedSupplementaryViewForElementOfKind:atIndexPath:withLayoutAttributes:applyAttributes:] + 148
5 UIKit 0x05a8fd16 -[UICollectionView _updateVisibleCellsNow:] + 4947
6 UIKit 0x05a94561 -[UICollectionView layoutSubviews] + 281
7 UIKit 0x0541352a -[UIView(CALayerDelegate) layoutSublayersOfLayer:] + 668
8 libobjc.A.dylib 0x03882771 -[NSObject performSelector:withObject:] + 70
9 QuartzCore 0x04fb2e47 -[CALayer layoutSublayers] + 144
10 QuartzCore 0x04fa6925 _ZN2CA5Layer16layout_if_neededEPNS_11TransactionE + 403
11 QuartzCore 0x04fb52de -[CALayer(CALayerPrivate) layoutBelowIfNeeded] + 44
12 UIKit 0x05404f08 -[UIView(Hierarchy) layoutBelowIfNeeded] + 738
13 UIKit 0x05404c11 -[UIView(Hierarchy) layoutIfNeeded] + 83
14 RxCocoa 0x02e411a2 _TFFE7RxCocoaP7RxSwift14ObservableType24subscribeProxyDataSourceuRd__S_17DelegateProxyTyperFT8ofObjectCSo6UIView10dataSourcePs9AnyObject_16retainDataSourceSb7bindingFTqd__GOS0_5Eventwx1E__T__PS0_10Disposable_U1_FT_T_ + 146
15 RxCocoa 0x02e45778 _TPA__TFFE7RxCocoaP7RxSwift14ObservableType24subscribeProxyDataSourceuRd__S_17DelegateProxyTyperFT8ofObjectCSo6UIView10dataSourcePs9AnyObject_16retainDataSourceSb7bindingFTqd__GOS0_5Eventwx1E__T__PS0_10Disposable_U1_FT_T_ + 72
16 RxSwift 0x029c9ee1 _TTRXFo___XFo_iT__iT__ + 17
17 RxSwift 0x029ea64c _TPA__TTRXFo___XFo_iT__iT__ + 60
18 RxSwift 0x029ea6ed _TFC7RxSwiftP33_AB3B9E8806A71B46FB498A7594F5E0D919AnonymousDisposable7disposefT_T_ + 141
19 RxSwift 0x0295621a _TTWC7RxSwiftP33_AB3B9E8806A71B46FB498A7594F5E0D919AnonymousDisposableS_10DisposableS_FS1_7disposefT_T_ + 26
20 RxSwift 0x029e4122 _TFC7RxSwift10DisposeBagD + 258
21 Atte 0x005ff1ec _TToFC4Atte27ItemOfferListViewControllerE + 460
22 libobjc.A.dylib 0x0386b44c _ZL27object_cxxDestructFromClassP11objc_objectP10objc_class + 116
23 libobjc.A.dylib 0x0386b3d3 object_cxxDestruct + 20
24 libobjc.A.dylib 0x03878f38 objc_destructInstance + 48
25 libobjc.A.dylib 0x03878f69 object_dispose + 20
26 UIKit 0x05544b5a -[UIResponder dealloc] + 106
27 UIKit 0x054e2ac7 -[UIViewController dealloc] + 2270
28 UIKit 0x05abb963 -[UICollectionViewController dealloc] + 220
29 UIKit 0x054deadb -[UIViewController release] + 89
30 CoreFoundation 0x04260d17 CFRelease + 743
31 CoreFoundation 0x04281dff -[__NSArrayI dealloc] + 79
32 libobjc.A.dylib 0x03881772 _ZN11objc_object17sidetable_releaseEb + 248
33 libobjc.A.dylib 0x03880e9b objc_release + 43
34 libobjc.A.dylib 0x03881d32 _ZN12_GLOBAL__N_119AutoreleasePoolPage3popEPv + 586
35 CoreFoundation 0x04282758 _CFAutoreleasePoolPop + 24
36 CoreFoundation 0x042b95fe __CFRunLoopRun + 2270
37 CoreFoundation 0x042b8a5b CFRunLoopRunSpecific + 443
38 CoreFoundation 0x042b888b CFRunLoopRunInMode + 123
39 GraphicsServices 0x0a4052c9 GSEventRunModal + 192
40 GraphicsServices 0x0a405106 GSEventRun + 104
41 UIKit 0x053800b6 UIApplicationMain + 1526
42 Atte 0x00e5fcc1 main + 145
43 libdyld.dylib 0x07c15ac9 start + 1
)
libc++abi.dylib: terminating with uncaught exception of type NSException
I found it was caused in this method and changing this method to this solved this issue for me.
I would like to open a PR if it is a right solution.
RxSwift/RxCocoa/RxBlocking/RxTest version/commit
_version or commit here_ RxSwift 3.1.0 to 3.3.1.
Platform/Environment
Xcode version:
8.2.1
Installation method:
I have multiple versions of Xcode installed:
Level of RxSwift knowledge:
Hi @yuzushioh ,
I've added that self.collectionView?.dataSource = nil because I've had similar issues with UITableView in prod.
It would cache numberOfRows from original data source and when deinit would switch to TableViewDataSourceNotSet, I would get a call to func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell -> crash.
The way I've solved that was to set the entire data source to nil, that seemed to clear internal cache for UITableView. Another way to clear it was to call, layoutIfNeeded on it.
This is how Dispose method for subscribeProxyDataSource proxy looks like.
return Disposables.create { [weak object] in
subscription.dispose()
unregisterDelegate.dispose()
object?.layoutIfNeeded()
}
Could you please try with the following code?
return Disposables.create { [weak object] in
subscription.dispose()
object?.layoutIfNeeded() // trying to flush the cache before delegate is cleared
unregisterDelegate.dispose()
}
If would be also great if you could provide some repro project.
Hi @kzaher
Thank you for explaining about the background! I tried in your suggested way and it seems to work fine馃憤馃徎 I will find some time and make a project for this issue. should I make a PR?
@yuzushioh yep 馃憤
Awesome find! This has been a consistent issue for me on anything less than iOS10 for a while too. Thumbs up!
Hi @yuzushioh ,
I've merged your PR. Could you please add a unit test for that also?
You can observe layoutIfNeeded and setDelegate methods and write a test that makes sure layoutIfNeeded is called first.
Thanks for merging! will do馃憤馃徎
Hi @yuzushioh ,
I've made some changes regarding the disposal logic and added unit tests. Could you please recheck does master branch work for you correctly?
@ishkawa could you also maybe give it a test run? I know you've reported some issues with the UITableView.
Hi @kzaher I checked and master branch works just great! Thanks for the unit tests馃憤
I'm still seeing this issue with the 3.6.1 release. Clearing the data source and delegate before the deinit of view controllers resolves this for now.
@sureshven I'm facing the same issue
Most helpful comment
Hi @yuzushioh ,
I've made some changes regarding the disposal logic and added unit tests. Could you please recheck does
masterbranch work for you correctly?@ishkawa could you also maybe give it a test run? I know you've reported some issues with the UITableView.