I got a rather complicated collectionView cell and I've noticed that if I scroll really fast on my collectionView it crashes the app.
One of the error I got is this:
negative or zero sizes are not supported in the flow layout
I noticed if I just return a float value e.g. 500, in my UICollectionView sizeForItemAtIndexPath:
method, it doesn't crash.
My collection view has dynamic cell heights.
I'm parsing HTML Attributed string in my sizeForItemAtIndexPath:
method using this library:
https://github.com/mmislam101/HTMLAttributedString
Anyone know what causes the above error message to occur in particular?
The other error I also see in my Bugsense report related to this crash is:
-[__NSArrayM objectAtIndex:]: index 2 beyond bounds [0 .. 1]
This happens when I'm scrolling too fast = /
Bugsense stacktrace shows the crash order method calls is:
1) collectionView:layout:sizeForItemAtIndexPath:
2) calculateFeedCellHeightForIndexPath: (this is one of my own method, not Apple's)
3) dynamicHeightForHTMLAttributedString:UsingWidth:AndFont: (this is one of my own method, not Apple's)
4) HTMLAttributedString attributedStringWithHtml:andBodyFont: line 35
5) HTMLAttributedString attributedString line 79
6) scrollViewDidScroll: line 174
7) setFeedFooterHeight:animated: line 124
My setFeedFooterHeight:animated: method is:
-(void)setFeedFooterHeight:(CGFloat)newHeight animated:(BOOL)animated
{
footerHeightConstraint.constant = newHeight;
if(animated)
{
[UIView animateWithDuration:0.35 animations:^{
[self layoutIfNeeded]; // <------ crash on this line it seems
}];
}
else
{
[self.feedFooterView layoutIfNeeded];
}
}
However, when I run the app straight from Xcode rather than Testflight as above, Xcode stops at step 5 above, which yields this piece of code:
- (NSAttributedString *)attributedString
{
__block NSString *css = @"<style>";
[_cssAttributes enumerateObjectsUsingBlock:^(NSString *cssAttribute, NSUInteger idx, BOOL *stop) {
css = [css stringByAppendingString:cssAttribute];
}];
css = [css stringByAppendingString:@"</style>"];
NSString *htmlBody = [_html stringByAppendingString:css];
NSStringEncoding encoding = NSUnicodeStringEncoding;
NSData *data = [htmlBody dataUsingEncoding:encoding];
NSDictionary *options = @{NSDocumentTypeDocumentAttribute : NSHTMLTextDocumentType,
NSCharacterEncodingDocumentAttribute : @(encoding)};
// app crashes here on this next line.
NSAttributedString *body = [[NSAttributedString alloc] initWithData:data
options:options
documentAttributes:nil
error:nil];
return body;
}
I read on other threads something about wrapping uicollectionview reload until uicollection.isTracking becomes false?
I tried that but didn't seem to help.
OK, I accidentally stumble upon the cause of that error.
It's related to the [collectionView.collectionFlowLayout invalidateLayout];
call.
I added a 1.0 second delay and the problem appears to be gone.
I think this is an iOS 8 bug related to UICollectionView's delegate/datasource methods, and / or NSAttributedString.
I can get this same crash in one project by creating an NSAttributedString
from HTML in sizeForItemAtIndexPath:
If I create an attributed string first in numberOfRows:
this stops the crash: so likely issue is something in UIKit not being initialised properly, or a buffer is being shared between the HTML parser and one of the UICollectionView
sizing methods.
Note: on iOS 7.1 I get a different exception: "UICollectionView recieved layout attributes for a cell with an index path that does not exist:"
Try this experiment: call something like:
NSData *data = [@"<a href=\"http://www.google.com\">link</a>" dataUsingEncoding:NSUnicodeStringEncoding];
NSAttributedString *s = [[NSAttributedString alloc] initWithData:data options:@{NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType} documentAttributes:nil error:nil];
in, say:
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
This seems to force something (a parser perhaps?) to be initialised, such that when I then use similar code in:
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath
it doesn't crash. Crazy town.
I'm going to download 8.1 beta 2 and test there, and will report back.