質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

89.13%

celloctionViewのcellの削除

解決済

回答 2

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 2,934

RyoTamura

score 19

collectionViewを使い選択した画像を表示させるようにしています。
画像を追加する際には

imageArray.append(image)
collectionView.reloadData()


でうまく表示できたのですが、削除する際に

imageArray.remove(at: indexPath.row)
collectionView.reloadData()


とするとエラーが発生してしまいます。
データ元の方は削除できているので、collectionViewのCellの数に問題があると思われるのですが解決策がわかりません。

performBatchUpdate()を使うという情報を見つけましたが、update(() -> void)の箇所に何を入力すればいいのか理解できませんでした。

エラー内容
イメージ説明

発生場所
イメージ説明

削除コード場所
アクションシートを使って画像を削除しようとしています。
イメージ説明

collectionViewのレイアウト
レイアウトは自作のものを使っています。

import UIKit

class TestCollectionViewLayout: UICollectionViewLayout {

    let numberColumns = 2 //列数
    var height:CGFloat = 200 //セルの高さ

    //レイアウト配列
    private var layoutData = [UICollectionViewLayoutAttributes]()

    //レイアウトを準備するメソッド
    override func prepare() {
        //全体の幅
        let allWidth = collectionView!.bounds.width - collectionView!.contentInset.left - collectionView!.contentInset.right

        let widthSecond = collectionView!.frame.width ///多分使わない

        //列の幅
        let columnWidth = widthSecond / CGFloat(numberColumns) ///元はallwidth
        height = columnWidth


        //座標
        var y:CGFloat = 0
        var x:CGFloat = 0

        //要素数ぶんループ
        for count in 0 ..< collectionView!.numberOfItems(inSection: 0) {

            let indexPath = NSIndexPath(item:count, section:0)

            //レイアウトの配列に位置とサイズを登録する。
            let frame = CGRect(x:x, y:y, width:columnWidth, height: height)
            let attributes = UICollectionViewLayoutAttributes(forCellWith: indexPath as IndexPath)
            attributes.frame = frame
            layoutData.append(attributes)

            //X座標を更新
            if(count % 2 == 0) {
                x = columnWidth
            } else {
                x = 0
            }


            //Y座標を更新
            if(count % 2 != 0){
                y = y + height
            }
        }
    }



    //レイアウトを返すメソッド
    override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
        return layoutData
    }



    //全体サイズを返すメソッド
    override var collectionViewContentSize:CGSize {
        //全体の幅
        let allWidth = collectionView!.bounds.width - collectionView!.contentInset.left - collectionView!.contentInset.right

        let widthSecond = collectionView!.frame.width///この辺いじった
        height = widthSecond / CGFloat(numberColumns)

        //全体の高さ
        let allHeight = CGFloat(collectionView!.numberOfItems(inSection: 0)) * height / 2

        return CGSize(width:widthSecond, height:allHeight) ////いじった
    }

}


collectionViewは1つだけです。

コンソール情報
btと入力した結果の全文です。

* thread #1, queue = 'com.apple.main-thread', stop reason = signal SIGABRT
    frame #0: 0x000000010da29d42 libsystem_kernel.dylib`__pthread_kill + 10
    frame #1: 0x000000010da61457 libsystem_pthread.dylib`pthread_kill + 90
    frame #2: 0x000000010d7bb88f libsystem_c.dylib`abort + 127
    frame #3: 0x000000010cc9bce5 libc++abi.dylib`abort_message + 245
    frame #4: 0x000000010ccb6cbd libc++abi.dylib`default_terminate_handler() + 265
    frame #5: 0x000000010a3923c4 libobjc.A.dylib`_objc_terminate() + 103
    frame #6: 0x000000010ccb3f29 libc++abi.dylib`std::__terminate(void (*)()) + 8
    frame #7: 0x000000010ccb3bbe libc++abi.dylib`__cxa_rethrow + 99
    frame #8: 0x000000010a3922dc libobjc.A.dylib`objc_exception_rethrow + 40
    frame #9: 0x000000010a8b8096 CoreFoundation`CFRunLoopRunSpecific + 534
    frame #10: 0x000000010e9cfa24 GraphicsServices`GSEventRunModal + 62
    frame #11: 0x000000010b43a134 UIKit`UIApplicationMain + 159
  * frame #12: 0x0000000108961877 cellectionView`main at AppDelegate.swift:13
    frame #13: 0x000000010d71365d libdyld.dylib`start + 1
    frame #14: 0x000000010d71365d libdyld.dylib`start + 1

情報不足で申し訳ありません。よろしくお願いいたします。

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • RyoTamura

    2017/08/02 16:32

    DispatchQueue.main.asyncAfter(deadline: .now() + 1.0)を使って1秒遅れでやってみたのですが、同様のエラーが発生してしまいました。

    キャンセル

  • fuzzball

    2017/08/02 16:34 編集

    質問に書かれている情報だけで検証してみましたが問題なく削除出来ました。CollectionViewのレイアウトに関する情報を書いて下さい。(他にも書いた方が良さそうな情報があったら書いて下さい)あと、CollectionViewは画面上に一つだけでしょうか?

    キャンセル

  • fuzzball

    2017/08/02 16:40

    もう一つ。止まったとき、Consoleに bt (Enter) と入力して表示される一覧を書いて下さい。(長過ぎるようなら後半は省略してもかまいません)

    キャンセル

回答 2

checkベストアンサー

+1

ちょっとググっただけですが、

collectionView.reloadData()
collectionView.collectionViewLayout.invalidateLayout()

で直りますか?

参考URL
iOS 10 bug: UICollectionView received layout attributes for a cell with an index path that does not exist

【追記】

TestCollectionViewLayout.prepare()内のループの前に、

layoutData.removeAll()

を追加して下さい。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/08/02 17:31

    回答に追記しました。

    キャンセル

  • 2017/08/03 20:40

    layoutData.removeAll()
    を追加したらできるようになりました!!
    本当にありがとうございます。

    今回のエラーの原因は自作レイアウトにあったのですね。
    簡潔でもいいので、なぜエラー原因を発見できたのか教えていただきたいです。

    キャンセル

  • 2017/08/04 00:06

    症状を再現出来たので、とりあえずprint文をあちこちに埋め込んだのですが、ループを抜けたところの print(layoutData) (実際にはindexPathのみ表示)を見て原因が分かりました。

    キャンセル

+1

https://developer.apple.com/documentation/uikit/uicollectionview/1618060-deleteitems

UICollectionView のdeleteItems(at: [indexPath]) 
を使うとどうでしょう?

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/08/02 15:43

    やってみましたが、同じエラーが発生してしまいました。

    キャンセル

  • 2017/08/02 16:27

    ごめんなさいこっちでした。

    mainスレッドにしないといけないのかも?

    // メインスレッドで実行
    DispatchQueue.main.async {
    collectionView.reloadData()
    }

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 89.13%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる