web-dev-qa-db-fra.com

les tailles négatives ou nulles ne sont pas prises en charge dans la présentation du flux

J'ai eu une cellule collectionView assez compliquée et j'ai remarqué que si je fais défiler très rapidement ma collectionView, l'application se bloque.

Une des erreurs que j'ai eu est la suivante:

negative or zero sizes are not supported in the flow layout

J'ai remarqué que si je venais de renvoyer une valeur float, par exemple 500, dans ma méthode UICollectionView sizeForItemAtIndexPath:, il ne se bloque pas.

Ma vue de collection a des hauteurs de cellules dynamiques.

J'analyse HTML Chaîne attribuée dans ma méthode sizeForItemAtIndexPath: à l'aide de cette bibliothèque:

https://github.com/mmislam101/HTMLAttributedString

Quelqu'un sait ce qui provoque le message d'erreur ci-dessus en particulier?

Mettre à jour

L'autre erreur que je vois aussi dans mon rapport Bugsense concernant ce crash est:

- [__ NSArrayM objectAtIndex:]: index 2 au-delà des limites [0 .. 1]

Cela se produit lorsque je fais défiler trop vite = /

Mise à jour 2

Bugsense stacktrace montre que les appels de méthode d'ordre de blocage sont:

1) collectionView: layout: sizeForItemAtIndexPath:

2) CalculateFeedCellHeightForIndexPath: (c'est l'une de mes propres méthodes, pas celle d'Apple)

3) dynamicHeightForHTMLAttributedString: UsingWidth: AndFont: (c'est l'une de mes propres méthodes, pas celle d'Apple)

4) HTMLAttributedString attribuéStringWithHtml: andBodyFont: ligne 35

5) Ligne HTMLAttributedString attribuéeString 79

6) scrollViewDidScroll: ligne 174

7) setFeedFooterHeight: animé: ligne 124

Mon méthode setFeedFooterHeight: animated: est:

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

Cependant, lorsque je lance l'application directement à partir de Xcode plutôt que de Testflight comme ci-dessus, Xcode s'arrête à l'étape 5 ci-dessus, ce qui donne ce 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;
}

J'ai lu sur d'autres discussions quelque chose sur l'emballage du rechargement de uicollectionview jusqu'à ce que uicollection.isTracking devienne faux?

J'ai essayé cela mais je n'ai pas semblé aider.

Mise à jour 3

OK, je suis accidentellement tombé sur la cause de cette erreur.

C'est lié à l'appel [collectionView.collectionFlowLayout invalidateLayout];.

J'ai ajouté un délai de 1,0 seconde et le problème semble avoir disparu.

14
Zhang

Je pense qu'il s'agit d'un bogue iOS 8 lié aux méthodes de délégué/source de données d'UICollectionView et/ou de NSAttributedString.

Je peux obtenir le même plantage dans un projet en créant un NSAttributedString à partir de HTML dans sizeForItemAtIndexPath: Si je crée une chaîne attribuée first in numberOfRows:, cela arrête le plantage: il est donc probable qu'un problème dans UIKit ne soit pas initialisé correctement ou un tampon est en cours de partage entre l'analyseur HTML et l'une des méthodes de redimensionnement UICollectionView.

Remarque: sur iOS 7.1, une exception différente est générée: "Les attributs de présentation reçus par UICollectionView pour une cellule avec un chemin d'index inexistant:"


Essayez cette expérience: appelez quelque chose comme:

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

dans, disons: 

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

Cela semble forcer quelque chose (un analyseur peut-être?) À être initialisé, de sorte que quand j'utilise un code similaire dans: 

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

ça ne plante pas. Ville folle.

Je vais télécharger la version 8.1 bêta 2 et l'essayer là-bas.

4
Philip McDermott

assurez-vous dans votre code où vous définissez collectionViewLayout.itemSize que la taille ne contient pas de valeur négative/nulle

1
Aleksey Mazurenko

Utilisez ceci 

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

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

}

0
CrazyPro007

Mon application était bloquée car j'envoyais une largeur de -6 à sizeForItemAt en raison d'une mauvaise logique de calcul.

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

largeur & hauteur devrait toujours être nombres non négatifs (> = 0)

0
keshav