web-dev-qa-db-ja.com

フローレイアウトでは負またはゼロのサイズはサポートされていません

かなり複雑なcollectionViewセルを取得しましたが、collectionViewで本当に速くスクロールすると、アプリがクラッシュすることに気づきました。

私が得たエラーの1つはこれです:

negative or zero sizes are not supported in the flow layout

私は浮動小数点値を返すだけであることに気づきました500、私のUICollectionView sizeForItemAtIndexPath:メソッドでは、クラッシュしません。

コレクションビューに動的なセルの高さがあります。

このライブラリを使用してsizeForItemAtIndexPath:メソッドでHTML属性付き文字列を解析しています:

https://github.com/mmislam101/HTMLAttributedString

上記のエラーメッセージが特に発生する原因を知っている人はいますか?

更新

このクラッシュに関連してBugsenseレポートに表示される他のエラーは次のとおりです。

-[__ NSArrayM objectAtIndex:]:範囲[0 .. 1]を超えるインデックス2

これは、スクロールが速すぎる場合に発生します= /

アップデート2

Bugsenseスタックトレースは、クラッシュオーダーメソッドの呼び出しが次のとおりであることを示しています。

1)collectionView:layout:sizeForItemAtIndexPath:

2)calculateFeedCellHeightForIndexPath:(これは私自身のメソッドの1つであり、Appleのメソッドではありません)

3)dynamicHeightForHTMLAttributedString:UsingWidth:AndFont:(これはAppleのメソッドではなく、私の独自のメソッドの1つです)

4)HTMLAttributedString attributedStringWithHtml:andBodyFont:行35

5)HTMLAttributedString attributedString 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];
    }
}

ただし、上記のようにTestflightではなくXcodeから直接アプリを実行すると、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;
}

他のスレッドでuicollection.isTrackingがfalseになるまでuicollectionviewリロードをラップすることについて何か読みましたか?

私はそれを試しましたが、助けにはならなかったようです。

アップデート3

OK、そのエラーの原因を偶然見つけました。

[collectionView.collectionFlowLayout invalidateLayout];呼び出しに関連しています。

1.0秒の遅延を追加したところ、問題は解消されたようです。

16
Zhang

これは、UICollectionViewのデリゲート/データソースメソッド、および/またはNSAttributedStringに関連するiOS 8のバグだと思います。

sizeForItemAtIndexPath:でHTMLからNSAttributedStringを作成することで、同じクラッシュを1つのプロジェクトで取得できます。属性付きの文字列を作成する場合firstnumberOfRows:では、これによりクラッシュが停止します。そのため、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ベータ2をダウンロードしてテストし、またレポートします。

5

コードで、collectionViewLayout.itemSizeを定義する場所で、サイズに負の値またはゼロの値が含まれていないことを確認してください

1

これを使って

func collectionView(_ collectionView:UICollectionView、layout collectionViewLayout:UICollectionViewLayout、sizeForItemAt indexPath:IndexPath)-> CGSize {

    if width <= 0 || height <= 0{
        return CGSize(width: 0, height: 0)
    }

}

0
CrazyPro007

間違った計算ロジックのため、幅を-6からsizeForItemAtに送信していたため、アプリがクラッシュしました

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

高さは常に非負の数(> = 0)である必要があります

0
keshav