The app is written in Swift 2.2 using Xcode 7.3.1.
I have a UITableView
with cells that have UICollectionView
with horizontal FlowLayout
. When I scroll the table view up and down really fast and without letting it stop on a device (iPad Air 2, iOS 9.3.2) or simulator, the app crashes with
EXC_BAD_ACCESS
in AppDelegate.
The app is not hitting a breakpoint set up in a view controller for didReceiveMemoryWarning()
.
It seems that the code crashes on
[UICollectionViewData invalidateItemsAtIndexPaths:]
or
[_UIFlowLayoutSection computeLayoutInRect:forSection:invalidating:]
followed by
0_dispatch_barrier_async_f_slow.
The stack trace doesn't point me to any line of app code.
Console stack trace for simulator (no console stack trace when crashing on device):
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '+[_UIFlowLayoutItem frame]: unrecognized selector sent to class 0x110f9ecc0'
*** First throw call stack:
(
0 CoreFoundation 0x000000011259cd85 __exceptionPreprocess + 165
1 libobjc.A.dylib 0x00000001137d3deb objc_exception_throw + 48
2 CoreFoundation 0x00000001125a5c3d +[NSObject(NSObject) doesNotRecognizeSelector:] + 205
3 CoreFoundation 0x00000001124ebcfa ___forwarding___ + 970
4 CoreFoundation 0x000000011259e1f8 __forwarding_prep_1___ + 120
5 UIKit 0x0000000110b1d8b5 -[UICollectionViewData invalidateItemsAtIndexPaths:] + 273
6 UIKit 0x0000000110ae26b7 -[UICollectionView _invalidateWithBlock:] + 62
7 UIKit 0x0000000110ae2a6f -[UICollectionView _invalidateLayoutWithContext:] + 656
8 UIKit 0x0000000110af0ad9 -[UICollectionViewLayout invalidateLayoutWithContext:] + 189
9 UIKit 0x0000000110afe2cc -[UICollectionViewFlowLayout invalidateLayoutWithContext:] + 604
10 libdispatch.dylib 0x0000000114257d9d _dispatch_call_block_and_release + 12
11 libdispatch.dylib 0x00000001142783eb _dispatch_client_callout + 8
12 libdispatch.dylib 0x00000001142601ef _dispatch_main_queue_callback_4CF + 1738
13 CoreFoundation 0x00000001124f60f9 __CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__ + 9
14 CoreFoundation 0x00000001124b7b99 __CFRunLoopRun + 2073
15 CoreFoundation 0x00000001124b70f8 CFRunLoopRunSpecific + 488
16 GraphicsServices 0x0000000114bcaad2 GSEventRunModal + 161
17 UIKit 0x000000011024cf09 UIApplicationMain + 171
18 market-touch 0x000000010d4cc472 main + 114
19 libdyld.dylib 0x00000001142ac92d start + 1
20 ??? 0x0000000000000001 0x0 + 1
)
libc++abi.dylib: terminating with uncaught exception of type NSException
Here's the stack trace (slightly different version here).
Why is that happening and is there anything I can do to prevent that?
EDIT: As per Doro's request, here is my cellForRowAtIndexPath:
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier(customCellNibName, forIndexPath: indexPath) as! CustomTableViewCell
//populating cell with data
return cell
}
I do not call func setCollectionViewLayout(_ layout: UICollectionViewLayout, animated animated: Bool)
at all.
The flow layout setup is done in IB.
Enabling zombie objects did not help me much, if at all. Here is a stack trace I got:
-[NSIndexPath frame]: unrecognized selector sent to instance 0xc000000012de4890
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[NSIndexPath frame]: unrecognized selector sent to instance 0xc000000012de4890'
*** First throw call stack:
(0x1815f6db0 0x180c5bf80 0x1815fdc4c 0x1815fabec 0x1814f8c5c 0x186fcccc0 0x186f9e688 0x1868de558 0x1868da0a4 0x1869ae9ec 0x1024f9a7c 0x1024f9a3c 0x1024ff4e4 0x1815acd50 0x1815aabb8 0x1814d4c50 0x182dbc088 0x1867b6088 0x1000c9f58 0x1810728b8)
libc++abi.dylib: terminating with uncaught exception of type NSException
EDIT 2:
In my CustomTableViewCell
's awakeFromNib()
method I have the following code:
if let layout = collectionView.collectionViewLayout as? UICollectionViewFlowLayout {
layout.estimatedItemSize = CGSizeMake(50, 22)
}
I have noticed that if I comment that out, I no longer get the crashes (although sometimes the whole table view freezes and is unusable). However, the collection view cells are not sized properly then. Compare: right vs wrong.
In IB, the Collection View Flow Layout -> Item Size is 50x22. The cell used for the collection view has one button in it, with height constraint 22pt. Here is the method for setting layout attributes for collection view cell:
override func preferredLayoutAttributesFittingAttributes(layoutAttributes: UICollectionViewLayoutAttributes) -> UICollectionViewLayoutAttributes {
let attributes = super.preferredLayoutAttributesFittingAttributes(layoutAttributes)
button.setTitle(symbol, forState: .Normal)
button.sizeToFit()
attributes.frame = button.frame
return attributes
}
The idea is to have these cells be 22pt high and of varying width (around 50pt), with the same distance between them. Can I achieve that without calling the code that, when commented out, prevents the crash?
Checkout this tutorial.
Basically, this could happen because of reusable essential of UITableViewCell. When you scroll tableView, it uses the same set of visible cells, and set the content from the your cellForRowAtIndexPath:
method.
Depending on your implementation, it seems UICollectionViewFlowLayout is deallocated at the specific point of time. I mean, you have call to
func setCollectionViewLayout(_ layout: UICollectionViewLayout,
animated animated: Bool)
inside cellForRowAtIndexPath:
and while you are scrolling, the new UICollectionViewLayout are allocated and set to the collectionView inside your cell. Enable Zombie objects in Edit Scheme -> Diagnostics -> Enable Zombie Objects. Check the correctness of current state.
It's hard to suggest any working snippet, but as an idea, try to set all the properties related to flow layout inside init method of uitableviewCell (only once) this will avoid re-allocating:
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = @"CellIdentifier";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (!cell)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
// set your flow layout or other stuff here
}
return cell;
}
Hope this helps.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With