【问题标题】:negative or zero sizes are not supported in the flow layout流布局中不支持负大小或零大小
【发布时间】:2014-12-02 16:11:55
【问题描述】:

我有一个相当复杂的 collectionView 单元格,我注意到如果我在 collectionView 上滚动得非常快,它会使应用程序崩溃。

我得到的错误之一是:

negative or zero sizes are not supported in the flow layout

我注意到如果我只返回一个浮点值,例如500,在我的 UICollectionView sizeForItemAtIndexPath: 方法中,它不会崩溃。

我的收藏视图具有动态单元格高度。

我正在使用这个库在我的 sizeForItemAtIndexPath: 方法中解析 HTML Attributed 字符串:

https://github.com/mmislam101/HTMLAttributedString

有谁知道具体是什么原因导致出现上述错误消息?

更新

我在 Bugsense 报告中还看到与此崩溃相关的另一个错误是:

-[__NSArrayM objectAtIndex:]:索引2超出范围[0 .. 1]

当我滚动太快时会发生这种情况 = /

更新 2

Bugsense 堆栈跟踪显示崩溃顺序方法调用是:

1) collectionView:layout:sizeForItemAtIndexPath:

2)calculateFeedCellHeightForIndexPath:(这是我自己的方法之一,不是苹果的)

3) dynamicHeightForHTMLAttributedString:UsingWidth:AndFont:(这是我自己的方法之一,不是苹果的)

4) HTMLAttributedString attributesStringWithHtml:andBodyFont: 第 35 行

5) HTMLAttributedString 属性字符串第 79 行

6) scrollViewDidScroll:第 174 行

7) setFeedFooterHeight:animated: line 124

我的 setFeedFooterHeight:animated: 方法是:

-(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];
    }
}

但是,当我直接从 Xcode 而不是上面的 Testflight 运行应用程序时,Xcode 会在上面的第 5 步停止,这会产生这段代码:

- (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;
}

我在其他线程上读到了一些关于包装 uicollectionview 重新加载直到 uicollection.isTracking 变为 false 的内容?

我试过了,但似乎没有帮助。

更新 3

好的,我偶然发现了导致该错误的原因。

这与[collectionView.collectionFlowLayout invalidateLayout];调用有关。

我添加了 1.0 秒的延迟,问题似乎消失了。

【问题讨论】:

  • 那么您的代码是否曾经返回零/负高度?什么时候?
  • 我尝试在 sizeForItemAtIndexPath 的返回语句之前执行 if(returnedHeight == 0) { NSLog(@"height is 0"; },但它永远不会到达该代码断点。
  • 不检查是否与零相等,检查&lt; 1
  • 在 Dropbox 中分享您的代码,以便我们了解更多详情?
  • T-T 我希望我可以,但这是公司不想披露的敏感信息。看来我一个人了。尽管如此,我还是感谢您的帮助。

标签: ios uicollectionview autolayout uicollectionviewcell


【解决方案1】:

我认为这是与 UICollectionView 的委托/数据源方法和/或 NSAttributedString 相关的 iOS 8 错误。

我可以通过在 sizeForItemAtIndexPath: 中从 HTML 创建一个 NSAttributedString 在一个项目中遇到同样的崩溃如果我在 numberOfRows: 中创建一个属性字符串 first 这将停止崩溃:很可能是问题是 UIKit 中的某些内容未正确初始化,或者在 HTML 解析器和 UICollectionView 大小调整方法之一之间共享缓冲区。

注意:在 iOS 7.1 上我得到一个不同的异常:“UICollectionView 收到了一个单元格的布局属性,其中的索引路径不存在:”


试试这个实验:调用类似:

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];

在,说:

- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section

这似乎迫使某些东西(也许是解析器?)被初始化,这样当我然后在中使用类似的代码时:

- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath

它不会崩溃。疯狂的小镇。

我将下载 8.1 beta 2 并在那里进行测试,然后会报告。

【讨论】:

  • 嗨菲利普,感谢您的意见。听起来你描述的场景与我的相符。在你说的 numberOfRows 方法中先做?我有点不情愿,这意味着我要做双倍的工作,即滚动会比现在慢,不是吗?或者你的意思是通过创建任何随机的 NSAttributedString 来强制解析器?我也尽量避免缓存,因为这很痛苦。我的页面有可删除的行和可更新的行,例如从 URL 加载的异步图像。下周我回到办公室时,我会试试你的建议。谢谢。
  • 是的,只要做一个任意字符串来强制解析器。无论如何我都在考虑缓存(因为你可能会在计算高度和单元格中做同样的工作),但实际上我可能会使用完整的 TextKit 而不是 UITextView - 我发现了许多琐碎的错误以使其稳定。
  • 即使使用 numberOfSections 中的附加代码仍然会发生。顺便说一句,如果上面的代码对您有用,您是否只需要在 viewDidLoad() 方法中而不是在 numberOfItems() 中执行一次?
  • 是的 viewDidLoad 应该可以工作:我只是想知道 collectionView 已经被实例化了。奇怪的是它对您的情况没有帮助:也许稍后再试?
【解决方案2】:

由于某些错误的计算逻辑,我向 sizeForItemAt 发送宽度为 -6 时,我的应用程序崩溃了

  func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
    return CGSize(width: width, height: height)
}

width & height 应始终为非负数 (>= 0)

【讨论】:

    【解决方案3】:

    确保在您定义 collectionViewLayout.itemSize 的代码中大小不包含负值/零值

    【讨论】:

      【解决方案4】:

      使用这个:

      func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
      
          if (width <= 0 || height <= 0) {
              return CGSize(width: 0, height: 0)
          }
      }
      

      【讨论】:

        猜你喜欢
        • 2015-09-10
        • 2011-11-29
        • 1970-01-01
        • 2015-04-30
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多