"La layout automatique est toujours requirejse après l'exécution de -layoutSubviews" avec la sous-class UITableViewCell

En utilisant XCode 4.5 et iOS 6, je développe une application avec une vue de table simple avec des cellules personnalisées. Je l'ai fait une centaine de fois dans iOS 5 et less, mais pour une raison quelconque, le nouveau système autoLayout me pose beaucoup de problèmes.

J'ai configuré ma vue de table et ma cellule prototype dans IB, ajouté des sous-vues et les ai câblées en tant que IBOutlets, puis j'ai configuré mon délégué et dataSource. Cependant maintenant, chaque fois que la première cellule est récupérée de cellForRowAtIndexPath , j'obtiens l'erreur suivante:

*** Échec de l'assertion dans – [ShopCell layoutSublayersOfLayer:], /SourceCache/UIKit_Sim/UIKit-2372/UIView.m:5776

*** Termination de l'application en raison d'une exception non interceptée 'NSInternalInconsistencyException', raison: 'Auto Layout est toujours requirejs après l'exécution de -layoutSubviews. L'implémentation de ShopCell de -layoutSubviews doit appeler super.

Je n'ai pas implémenté une méthode -layoutSubviews dans ma cellule sous-classée (ShopCell), et même lorsque j'essaye de le faire et ajoute le super appel comme il me le suggère, j'ai toujours la même erreur. Si je supprime les sous-vues de la cellule dans IB, et que je le change en UITableViewCell standard, tout fonctionne comme prévu, bien que je ne dispose bien sûr d'aucune donnée dans mes cellules.

Je suis presque certain qu'il y a quelque chose de simple qui me manque, mais je ne trouve pas de documentation ou de guides pour suggérer ce que j'ai fait de mal. Toute aide serait appréciée.

Edit: J'ai juste essayé de le changer en UITableViewCell dans IB et de laisser toutes les sous-vues en place, toujours la même erreur.

J'ai rencontré le même problème en ajoutant manuellement des contraintes dans le code. Dans le code, je faisais ce qui suit:

 { [self setTranslatesAutoresizingMaskIntoConstraints:YES]; [self addSubview:someView]; [self addSubview:someOtherView]; [self addConstraint:...]; } 

Hypothèse

D'après ce que je peux dire, le problème est que lorsque vous désactivez translatesAutoresizingMaskIntoConstraints , UITableViewCell commence à utiliser Auto Layout et échoue naturellement parce que l'implémentation sous-jacente de layoutSublayersForLayer n'appelle pas super. Quelqu'un avec Hopper ou un autre outil peut le confirmer. Puisque vous utilisez IB, vous vous requestz probablement pourquoi c'est un problème … et c'est parce que IB désactive automatiquement translatesAutoresizingMaskIntoConstraints pour les vues auxquelles il ajoute des contraintes (il appenda automatiquement une contrainte de largeur et de hauteur à leur place).

Solution

Ma solution consistait à tout déplacer vers contentView .

 { [self.contentView addSubview:someView]; [self.contentView addSubview:someOtherView]; [self.contentView addConstraint:...]; } 

Je ne suis pas sûr à 100% si cela fonctionnera dans Interface Builder, mais si vous mettez tout hors de votre cellule (en supposant que vous avez quelque chose directement dessus), alors cela devrait fonctionner. J'espère que cela vous aide!

Apparemment, l'implémentation layoutSubviews de UITableViewCell n'appelle pas super, ce qui est un problème avec la layout automatique. Je serais intéressé de voir si la suppression de la catégorie ci-dessous dans les projets fixe des choses. Cela a aidé dans un projet de test.

 #import <objc/runtime.h> #import <objc/message.h> @implementation UITableViewCell (FixUITableViewCellAutolayoutIHope) + (void)load { Method existing = class_getInstanceMethod(self, @selector(layoutSubviews)); Method new = class_getInstanceMethod(self, @selector(_autolayout_replacementLayoutSubviews)); method_exchangeImplementations(existing, new); } - (void)_autolayout_replacementLayoutSubviews { [super layoutSubviews]; [self _autolayout_replacementLayoutSubviews]; // not recursive due to method swizzling [super layoutSubviews]; } @end 

J'appendai que le problème est apparu lorsque j'utilise un backgroundView sur la cellule du tableau, car il est ajouté en tant que sous-vue à la cellule (alors que la plupart des sous-vues devraient être ajoutées à contentView, ce qui devrait normalement fonctionner).

Note: Il semble que ce bug est corrigé dans iOS7; J'ai été en mesure de supprimer ce code, ou au less append une vérification de l'exécution de sorte que c'est seulement fait si fonctionnant sur iOS6.

J'ai eu le même bug pendant quelques mois. Mais j'ai trouvé quel était le problème.

Lorsque je crée un file IB, un UIView est déjà ajouté. Si vous utilisez cette vue, l'application ne plante pas lorsque la layout automatique est désactivée (mais il existe d'autres problèmes). Lorsque vous utilisez la layout automatique, vous devez sélectionner la vue correcte dans la bibliothèque d'objects: UITableViewCell .

En fait, vous devriez toujours utiliser cet élément car toutes les sous-vues sont ajoutées au contentView de UITableViewCell .

C'est tout. Tout ira bien.

J'ai eu le même problème avec la fonction personnalisée UITableViewHeaderFooterView + xib.

J'ai vu quelques réponses ici, mais j'ai trouvé quelle implémentation -layoutSubviews dans ma class de vue de pied de page personnalisée résout problème:

 -(void)layoutSubviews { [super layoutSubviews]; [self layoutIfNeeded]; // this line is key } 

Je voyais cela comme une conséquence de la modification des contraintes dans mon implémentation de layoutSubviews. Déplacer l'appel à super du début à la fin de la méthode a résolu le problème.

Avait le même problème dans iOS 7 (iOS 8 semble fixer). La solution pour moi consistait à appeler [self.view layoutIfNeeded] à la fin de ma méthode viewDidLayoutSubviews .

J'ai eu le même problème. Le problème était dans la façon dont je créais la cellule Xib. J'ai créé un Xib comme normal et juste changé le type de "UIView" par défaut à ma class UITableViewCell personnalisée. La méthode correcte consiste à supprimer d'abord l'affichage par défaut, puis à faire glisser l'object de la cellule de vue de la table sur le xib. Plus de détails ici: http://allplayers.github.io/blog/2012/11/18/Custom-UITableViewCell-With-NIB/

J'ai résolu le problème en désactivant "Autolayout" pour toutes les sous-vues de ma cellule de vue de table personnalisée.

Dans le file xib d'une cellule personnalisée, select une sous-vue et décochez la case Inspecteur de files> Document Interface Builder> Utiliser la layout automatique

J'ai eu un problème similaire non sur UITableViewCell mais plutôt sur UITableView lui-même. Parce que c'est le premier résultat dans Google, je l'afficherai ici. Il s'est avéré que viewForHeaderInSection était le problème. J'ai créé un UITableViewHeaderFooterView et définissez translatesAutoresizingMaskIntoConstraints à NO . Maintenant, voici la partie intéressante:

IOS 7:

 // don't do this on iOS 7 sectionHeader.translatesAutoresizingMaskIntoConstraints = NO; 

Si je fais cela, l'application se bloque avec

La layout automatique est toujours nécessaire après l'exécution des sous-affichages. L'implémentation de UITableView de -layoutSubviews doit appeler super.

OK, je pensais que vous ne pouvez pas utiliser la layout automatique sur un en-tête de vue de table et seulement sur les sous-vues. Mais ce n'est pas toute la vérité comme vous le verrez plus tard. Pour résumer: Ne désactivez pas le masque de redimensionnement automatique pour l'en-tête sur iOS 7. Sinon, cela fonctionne très bien.

iOS 8:

 // you have to do this, otherwise you get an auto layout error sectionHeader.translatesAutoresizingMaskIntoConstraints = NO; 

Si je ne l'utiliserais pas, j'obtiendrais la sortie suivante:

Impossible de satisfaire simultanément les contraintes.

Pour iOS 8, vous devez désactiver le masque de redimensionnement automatique pour l'en-tête.

Je ne sais pas pourquoi il se comporte de cette façon, mais il semble que Apple a corrigé certaines choses dans iOS 8 et la layout automatique fonctionne différemment sur iOS 7 et iOS 8.

Comme mentionné ci-dessus, lorsque vous créez une vue à utiliser dans UITableView, vous devez supprimer la vue créée par défaut et faire glisser une vue UITableViewCell ou UITableViewHeaderFooterView en tant que vue racine. Cependant, il existe un moyen de réparer le XIB au cas où vous auriez manqué cette partie. Vous devez ouvrir le file XIB dans un éditeur de text et dans la balise racine et son enfant direct append / modifier l'atsortingbut translatesAutoresizingMaskIntoConstraints à YES , par exemple

<view contentMode="scaleToFill" horizontalHuggingPriority="1000" id="1" translatesAutoresizingMaskIntoConstraints="YES" customClass="MXWCollapsibleTableHeaderView">

Je rencontre ceci et il semble qu'il soit lié aux sous-classs UITableViewCell en tant que cellules prototypes qui ont spécifiquement d'autres sous-classs UIView personnalisées qui leur sont ajoutées. J'insiste sur la "coutume" ici parce que j'ai réussi avec des cellules qui ont juste des enfants UIKit, mais ça tombe quand j'essaie de build les contraintes pour les vues que j'ai créées sur mesure, en jetant l'erreur dans la question des auteurs.

J'ai dû séparer mes cellules en pointes indépendantes qui n'utilisent pas AutoLayout.

Espérons que Apple nettoiera ce gâchis.

J'ai rencontré celui-ci parce que j'avais initialement ajouté un UIView au lieu d'un UITableViewCell à un file xib.

J'ai éliminé cette erreur en découplant le connecteur backgroundView de mes connecteurs UIImageView et accessoryView arrière-plan de mes personnalisations UIButton . Je soupçonne que ceux-ci n'étaient pas destinés à être utilisés comme je les utilisais.

J'avais rencontré ce problème la première fois aujourd'hui. Jusqu'à présent, j'avais une expérience variée dans l'utilisation des sous-classs de prototype UITableViewCell mais je n'ai jamais rencontré ce problème. Ce qui était différent à propos de la cellule avec laquelle je travaillais, c'est que j'avais un IBOutlet pour le -backgroundView que j'utilisais pour colorer la cellule. J'ai trouvé que si je créais une nouvelle propriété et que j'ajoutais encore un nouveau UIView qui étirait la durée de la cellule entière, cette affirmation disparut. Pour vérifier cela était la cause, je suis returnné à attacher cette vue à la sortie backgroundView et l'assertion a réapparu. Jusqu'à présent, aucun autre problème d'utilisation de AutoLayout dans un prototype sous-classé UITableViewCell depuis que j'ai fait ce changement.

Ajoutez vos sous-vues au contentView de la cellule au lieu de la cellule elle-même. Donc, au lieu de:

[self addSubview:someView];

Tu dois utiliser

[self.contentView addSubview:someView];

Je n'ai pas trouvé de solution appropriée à ce problème mais vous pouvez le corriger en utilisant des frameworks et en ne définissant pas la propriété translatesAutoresizingMaskIntoConstraints sur No (par défaut, oui, donc ne le définissez pas)

 CGRect headerViewFrame = CGRectMake(0,0,320,60); //Frame for your header/footer view UIView *tableHeaderView = [[UIView alloc] initWithFrame:headerViewFrame]; tableHeaderView.translatesAutoresizingMaskIntoConstraints = Yes; //Or don't set it at all [self.tableView setTableHeaderView:tableHeaderView]; 

J'ai vécu la même chose. Il s'est avéré que si vous ajoutez par programme une sous-vue à partir de votre ShopCell .xib / storyboard, cela utilise la layout automatique, en tant que sous-vue à une autre vue, cette exception peut être levée, selon la configuration de vos contraintes. Ma conjecture est que les contraintes créées dans IB sont ce qui crée les problèmes lors de l'ajout programmé d'une vue en sous-vue, puisqu'elle maintient ensuite les contraintes de viewA -> viewB et vous pouvez append viewB comme sous-vue de viewC. Vous l'avez (cette phrase me confond même)?

Dans ma situation – puisque ce sont des vues très simples qui ont causé le problème – j'ai créé les vues par programme et non dans IB. Cela l'a résolu. Vous pouvez extraire ces vues vers d'autres files xib et désactiver la layout automatique pour celles-ci. Je suppose que ça marcherait.

Dans certaines situations, cela résout facilement le problème de layout (en fonction de votre layout). Dans votre sous-class UITableView, dans awakeFromNib ou init, définissez le masque d'autoresizing:

 self.contentView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; 

Par defaut, il est défini sur UIViewAutoresizingNone

Dans mon cas,

L'UIImageView référencé pour la layout automatique de UITableView est assigné à backgroundView de UITableView.

 self.tableView.backgroundView = self.tableBackgroundImageView; 

J'ai donc supprimé UIImageView pour backgroundView de l'UIView (vue racine) et réinitialiser (supprimer) toute reference de disposition automatique à cette UIImageView. J'ai placé ce UIImageView pour l'arrière-plan à l'extérieur de l'UIView (vue racine). Et puis assignez à l'arrière-plan de l'UITableView dans le code.

Puis fixé.

J'ai trouvé la solution.

Dans mon cas, j'ai créé la vue de la cellule dans le storyboard (avec la layout automatique activée) et j'ai défini l'interface UITableViewCell personnalisée dans mon ViewController.m, je dois déplacer l'interface vers ViewController.h.

J'ai rencontré le même problème lorsque j'utilise le storyboard pour créer le UITableViewCell personnalisé. Heureusement, j'ai trouvé le problème, parce que je sortie le accessoryView ([UITableViewCell setAccessoryView:]) à UIButton que j'ai ajouté à la cellule.

Donc, il s'est produit dans mon projet lorsqu'il est exécuté sur l'iOS6.

Solution

Je relâche la sortie entre accessoireView et mon button qui contenait la cellule personnalisée.

Proposition

Vous ne devez pas utiliser les éléments natifs de UITableViewCell et le modifier.

Ce problème peut être provoqué en oubliant d'appeler [super viewDidAppear:] dans viewDidAppear , mais je suis sûr que ce n'est pas la seule cause.

J'avais exactement le même problème. Voici le problème avec mon projet:
Lorsque j'ai travaillé sur Interface Builder pour créer un UITableViewCell personnalisé, j'ai déplacé une vue à la place d'une cellule de vue de table à partir du volet de collection d'objects dans Xcode
en tant que cellule de table personnalisée.
Si vous êtes dans la même situation, voici la solution:
Supprimez la vue dans le constructor d'interface, assurez-vous de faire glisser une cellule de vue de table depuis le volet de collection d'objects et de refaire la vue de cellule de tableau personnalisée. Vous pouvez copyr les objects dans l'ancienne vue et les coller dans le canevas pour la nouvelle cellule de vue de table.

J'ai eu un problème très similaire avec une vue de pied de table que je mettais en Xcode 6, iOS 7+. La solution était au format du file nib. Apparemment, il était coincé au format Xcode 4 ou quelque chose. Modification des parameters de file à "ouvre dans: Xcode 6.0" (ou par défaut, d'ailleurs), instantanément réparé. J'ai trouvé la solution par hasard: ça me rendait fou, alors j'ai supprimé tout le file et créé à nouveau, évidemment avec les parameters par défaut. Je n'ai aucune idée pourquoi simplement éditer le file dans le dernier Xcode ne l'a pas converti en format Xcode 5+, comme cela arrive habituellement.

F

Je suis allé eu le même problème. Je suis allé à mon DetailViewController et renommé l'identifiant à UIView. Il était précédemment sur UITableView. Cela a réglé le problème. Ce problème ne doit pas être dans votre DetailViewController. Cela pourrait être dans n'importe quel autre. Essayez de le renommer en identifiant respecté.

J'ai eu un problème similaire avec les cellules de vue de table statique dans IB. L'une des cellules avait une sous-vue dont la class avait été modifiée par erreur en une sous-class de UITextfield. Le compilateur n'a donné aucun avertissement / erreur. Mais lors de l'exécution, le système n'a pas pu charger le controller de vue avec le plantage mentionné ci-dessus.

La question est le séquençage des appels de layout aux sous-vues:

Check-out

Apparaît dans iOS <8

Solution: modifier les contraintes avant appel super layoutSubviews

 - (void)layoutSubviews { [self _updateConstraints]; [super layoutSubviews]; } 

J'ai modifié la réponse de Carl Lindberg pour substituer UITableView place et il a commencé à travailler pour moi:

UITableView + AutoLayoutFix.h

 @interface UITableView (AutoLayoutFix) @end 

UITableView + AutoLayoutFix.m

 #import <objc/runtime.h> @implementation UITableView (AutoLayoutFix) + (void)load { Method existingMethod = class_getInstanceMethod(self, @selector(layoutSubviews)); Method newMethod = class_getInstanceMethod(self, @selector(_autolayout_replacementLayoutSubviews)); method_exchangeImplementations(existingMethod, newMethod); } - (void)_autolayout_replacementLayoutSubviews { [super layoutSubviews]; [self _autolayout_replacementLayoutSubviews]; // not recursive due to method swizzling [super layoutSubviews]; } @end 

Ensuite, dans MyViewController.m je viens d'importer la catégorie:

 #import "UITableView+AutoLayoutFix.h" 

J'ai rencontré le même problème et finalement trouvé la raison était que j'ai ajouté une contrainte à UITableViewCell, qui devrait être le contentView de UITableViewCell . Quand j'ai changé la contrainte tout s'est bien passé!