UICollectionViewまたはオオカミと踊る



UICollectionViewは、iOS 6で導入されたUIKitクラスです。厳密に言えば、これは画面上にアイテムのコレクションを表示できるクラスです。 コレクションの構造は完全に任意ですが、通常、UICollectionViewは、セル、ヘッダー、およびフッターを含むあらゆる種類のグリッドのようなコントロールに使用されます。 このクラスがどれほど抽象的であるかを認識して、Apple開発者はレイアウトを作成するための強力なメカニズムを作成しました。 概して、UITableViewでさえUICollectionViewの具体的な実装です。 このクラスの機能は、ある意味で素晴らしいです。 しかし、この記事はそれについてではありません。



Apple DevelopersのAchilles Heelは、「自動的に」機能するKFORを常に作りたいと願っています。 これを行うだけで、クラスは正しいことになるでしょう。 残念ながら、これは常に機能するとは限りません。 そして、UICollectionViewは代表的な例です。 iOS 6のリリースから現在(iOS 7.0.4)まで、このクラスには非常に多くのバグが含まれていますが、これらのバグは非常に難しく、対処するのが面倒です。 「内部」で何が起こっているかを推測し、pokeメソッドを使用してUICollectionViewを正常に機能させる必要があります。 私が購入した松葉杖の数はすでにそのような割合に達しており、見つかった既知のバグと解決策を共有することにしました。



誰も気にしない-あなたは猫の下で歓迎されています。



現実



バグの説明を始める前に、UICollectionViewが松葉杖なしで安定して動作する「完璧なシナリオ」を説明しようとします。 通常、これはUICollectionViewであり、ヘッダーとフッターはなく、セルのみがあります。 コントローラーがメモリに読み込まれると(viewDidLoad :)、UICollectionView -reloadDataメソッドが呼び出されます。 アニメーション化された削除、移動、および挿入は行われません。 松葉杖のないUICollectionViewの理想的なシナリオを次に示します。 ご覧のとおり、かなり限られています。



リストのバグに遭遇しないように、すぐに予約してください。これについては、以下で説明します。 それぞれのバグは、あなたが持っていないかもしれない特定の状態にありました。 また、各ソリューションは私の特定のケースで役立ちました。それがあなたを助けるという保証はなく、今後のiOSリリースでも引き続き機能するという保証はありません。 多くの松葉杖はManyいように見えますが、どの松葉杖はくないですか? ただし、何か助けていただければ幸いです=)。 行こう!



iOS 6 + iOS 7



1.最初のUICollectionViewCellをセクションに挿入することはできません。 また、最後に残ったUICollectionViewCellを削除することはできません。 これを行おうとすると、デバッグビルドでクラッシュし、リリースビルドで予期しない動作が発生します。



***キャッチされない例外 'NSInternalInconsistencyException'によるアプリの終了、理由: 'コレクションビューにアイテムが1つしかない場合のグローバルインデックス1のインデックスパスの要求'


コメント UICollectionViewの最も有名なバグ。 Appleバグトラッカーのレーダーを開きます。 最も一般的で安定したソリューションは、reloadDataを呼び出すことです。 try-catchブロックでinsertItemsAtIndexPaths:メソッドを呼び出すと役立つ場合があります(はい、脚は容赦なく撃たれました)。



@try { [self.collectionView insertItemsAtIndexPaths:indexPaths]; } @catch (NSException *exception) {}
      
      





おそらく使用する価値はないが、言及する価値がある別のソリューションは、performBatchUpdatesブロック内でreloadDataを呼び出すことです。



 [self.collectionView performBatchUpdates:^{ [self.collectionView reloadData]; } completion:nil];
      
      





2. performBatchUpdatesブロックなしで2つのアニメーション操作を同時に実行しようとすると、アプリケーションがクラッシュします。



***キャッチされない例外 'NSInternalInconsistencyException'によるアプリの終了、理由: '無効な更新:無効なセクション数。 更新後のコレクションビューに含まれるセクションの数(1)は、更新前のコレクションビューに含まれるセクションの数(0)に、挿入または削除されたセクションの数を加えたり引いたり(0を挿入、0削除)。 '


コメント この段落は取るに足らないように見えるかもしれませんが、実際には非常に重要です。 UICollectionViewに関する私の個人的な問題の80%は、いくつかのアニメーションをグループ化する必要があるときに発生しました。 特に、これはNSFetchedResultsControllerとCoreDataデータベースの更新によるものです。 Core Dataの更新プログラムを正しく使用できるようにするAsh Furrowのオープンソースソリューションがあります。



3. 1つのperformBatchUpdatesブロックでセクションとセルを更新することはできません。 アップグレードとは、挿入または削除を指します。



***キャッチされない例外 'NSInternalInconsistencyException'によるアプリの終了、理由: '無効な更新:無効なセクション数。 更新後のコレクションビューに含まれるセクションの数(1)は、更新前のコレクションビューに含まれるセクションの数(0)に、挿入または削除されたセクションの数を加えたり引いたり(0を挿入、0削除)。 '


コメント かなり奇妙な問題です。2つの連続したperformBatchUpdatesブロックが役立ちます。最初のブロックセクションでは、2番目のブロックセルで更新されます。



4. reloadDataを呼び出した直後にperformBatchUpdatesを呼び出すことはできません。



セクション0を削除しようとしますが、更新前にセクションは0個しかありません


コメント UITableViewとは異なり、UICollectionViewのreloadDataは非同期に動作するようです。



2014年2月5日の更新 。reloadDataを同期的に呼び出す松葉杖メソッドがあります。 これを行うには、新しいUICollectionViewLayoutオブジェクトを作成し、メソッドを呼び出します



 [collectionView setCollectionViewLayout:layout animated:NO];
      
      





内部のメソッドは、プライベート同期reloadDataを呼び出します。 このソリューションは、UICollectionViewに既に要素/セルが存在する場合にのみ機能します。 セルがない場合-初めて何も起こりませんが、2回目はクラッシュします。 ハックを提案してくれたユーザーPALKOVNIKに感謝します。



2014年3月3日の更新。UICollectionViewを同期的に更新する2番目の松葉杖の方法:



 [collection.collectionView reloadData]; [collection.collectionView performBatchUpdates:nil completion:nil];
      
      







5. UICollectionViewFlowLayoutを使用する場合、headerSizeまたはfooterSizeがゼロ以外の場合、collectionView:viewForSupplementaryElementOfKind:atIndexPath:メソッドはnilを返してはなりません。そうしないとクラッシュします。



***キャッチされない例外 'NSInternalInconsistencyException'によるアプリの終了、理由: '-collectionViewから返されたビュー:viewForSupplementaryElementOfKind:atIndexPath(UICollectionElementKindSectionFooter、<NSIndexPath:0x8e55df0> {length = 2} by not = 0-retrieved呼び出し-dequeueReusableSupplementaryViewOfKind:withReuseIdentifier:forIndexPath:またはis nil((null)) '


コメント ヘッダーまたはフッターのないUICollectionViewがある場合、デリゲートメソッドを定義する必要があります



  -(CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewFlowLayout *)collectionViewLayout referenceSizeForHeaderInSection:(NSInteger)sectionNumber
      
      





このセクションにヘッダーがない場合は、CGSizeZeroを返します。



iOS 6



1. UICollectionViewFLowLayout。 セルのないセクションがあり、デリゲートメソッドcollectionView:layout:referenceSizeForHeaderInSection:を定義していない場合、運が悪く、ランタイムがクラッシュします。



***アサーションエラー-[UICollectionViewData indexPathForItemAtGlobalIndex:]

コレクションビューにアイテムが0個しかない場合のグローバルインデックス805306368のインデックスパスのリクエスト


コメント collectionView:layout:referenceSizeForHeaderInSection:メソッドを定義する必要があり、セクションにセルがない場合はCGSizeZeroを返します。



2. reloadCollectionを呼び出した後、UICollectionViewDatasourceメソッドが明らかにそうではないという事実にもかかわらず、古いセルがそのまま残ることがあります。 UICollectionViewがキーボードまたは別のUIViewによって閉じられている場合は特に一般的です。 残念ながら、解決策はありません。



iOS 7



1.セルがセクションの最後であり、UICollectionViewにフッターが存在する場合、別のセクションのこのセルに対してmoveItemAtIndexPath:toIndexPath:メソッドを呼び出すと、フォールにつながります。



キャッチされない例外 'NSInternalInconsistencyException'によるアプリの終了、理由: '-layoutAttributesForSupplementaryElementOfKindのUICollectionViewLayoutAttributesインスタンスがありません:パス<NSIndexPath:0xc054730> = length = 2のUICollectionElementKindSectionFooter


コメント この問題は、セクションの最初のアイテムの挿入と削除に非常に似ているため、ソリューションは同じです。アイテムが最後の場合はreloadDataを呼び出します。



2. UICollectionViewが画面に表示されていないときにセクションを削除すると、フォールにつながります。



***アサーションエラー-[UICollectionViewData validateLayoutInRect:]、/ SourceCache / UIKit_Sim / UIKit-2903.23 / UICollectionViewData.mhaps41

2014-01-10 17:34:55.198 SMS-Bank [47090:70b] ***キャッチされない例外 'NSInternalInconsistencyException'によるアプリの終了、理由: 'UICollectionViewは、存在しないインデックスパスを持つセルのレイアウト属性を受け取りました: <NSIndexPath:0xc000000000000056> {長さ= 2、パス= 1-0} '


コメント UICollectionViewが消える瞬間に、デリゲートとデータソースを無効にします。



 self.collectionView.delegate = nil; self.collectionView.dataSource = nil;
      
      







3. iOSシミュレーター、iPad 2およびiPad 3は、UICollectionViewCellの再利用を使用しません。 また、アクセシビリティショートカットが有効になっていると、再構築が失敗する場合があります。



コメント



スタックの詳細については、 http//stackoverflow.com/questions/19276509/uicollectionview-do-not-reuse-cellsをご覧ください。

レーダー: http : //openradar.appspot.com/15357491



終わり



リストは完全にはほど遠いかもしれませんが、残念ながらUICollectionViewはかなり不安定です。 いつかApple開発者がそれを思い起こさせることを望みます。 それまでの間、UICollectionViewでの便利な作業のために作成されたライブラリをお勧めします



実際、著者がこの記事に記載されているバグのほとんどを発見したのは、このライブラリの作成中です。 このフレームワークの目標はiOS SDKのバグを修正することではありませんでしたが、今日ではiOS 6およびiOS 7に追加された松葉杖が重要な機能の1つになりました。 UICollectionView + NSInternalInconsistencyExceptionと呼ばれる悪夢を忘れる能力は貴重です。 代替ソリューション、または他のUICollectionViewバグに関する情報がある場合は、コメントで共有してください!



ご清聴ありがとうございました!



All Articles