Почему UICollectionView reloadData разбивает мое приложение?

Я использую uicollectionview для отображения некоторых фотографий, и у меня есть кнопка, которая позволяет пользователю удалить выбранную фотографию.

Это работает отлично, если я не пытаюсь удалить последнюю фотографию в массиве фотографий, используемых для заполнения uicollectionview. Т.е. если будет 5 фотографий, то возникнет проблема, если пользователь удалит 5-ю фотографию, а не 1-ю, 2-ю, 3-ю или 4-ю. Когда я пытаюсь удалить 5-ю фотографию, она вылетает на reloadData() со следующей ошибкой

Завершение работы приложения из-за необработанного исключения "NSInternalInconsistencyException", причина: "попытка удалить элемент 4 из раздела 0, который содержит только 4 элемента перед обновлением"

Я не понимаю, почему это произошло... В ошибке даже упоминается "попытка удаления", но я никогда не говорил, что удаляю что-либо. Я просто изменил источник, а затем попросил его обновить. Также в сообщении об ошибке говорится, что раздел содержит только 4 элемента перед обновлением, когда на самом деле их было 5 фотографий. Зачем?

Немного больше информации о том, что я делаю и как (используя Swift)...

У меня есть ProgressPhotoSheetClass, из которого я создал экземпляр объекта progressPhotoSheet

этот объект progressPhotoSheet имеет массив фотографий, и фотографии могут иметь приоритеты, такие как идентификатор фотографии, заголовок и т. д.

в моем количестве предметов в разделе я использую

var numPics: Int = progressPhotoSheet.progressPhotos.count
return numPics

в моем cellForItemAtIndexPath я использую

let cell = collectionView.dequeueReusableCellWithReuseIdentifier(reuseIdentifier, forIndexPath: indexPath) as! PhotoHolder
cell.photoTitle.text = progressPhotoSheet.progressPhotos[indexPath.row].photoName

...так далее..

При удалении элемента я использую

progressPhotoSheet.deletePhoto(progressPhotoSheet.progressPhotos[indexPath.row].photoId)

который удаляет фотографию с устройства и из моих основных данных, а затем перезагружает progressPhotoSheet.progressPhotos от использования измененных основных данных, так что теперь это точно так, как было раньше, но без удаленной фотографии.

Я тогда звоню

self.collectionView.reloadData()

Который должен обновить UICollectionView для новых данных

Я мог бы понять, если бы чувствовалось несоответствие между тем, что должно быть в представлении коллекции, и тем, что находится в источнике данных, если бы я использовал self.collectionView.deleteItemsAtIndexPaths(indexPaths), потому что это означало бы игнорировать, чтобы заставить их соответствовать нам нужно удалить один элемент - здесь есть вероятность, что что-то может не соответствовать.. Но, конечно, при использовании self.collectionView.reloadData() не имеет значения, какие изменения были внесены, следует просто посмотреть, какие данные есть в данный момент, и соответствующим образом обновить UICollectionView....

Итак, мой вопрос... Почему я получаю эту ошибку и что я должен сделать, чтобы исправить ситуацию, чтобы я не получил ее?

Изменить, чтобы включить больше информации

Вот мой код телефото

func deletePhoto(photoId: Int) {

    // Set up Core Data Managed Object Context
    let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
    let managedContext = appDelegate.managedObjectContext!



    // Fetch correct photo
    let fetchRequest = NSFetchRequest(entityName: "CDProgressPhoto")
    fetchRequest.predicate = NSPredicate(format: "photoId = %@", String(photoId))

    // Save
    if let fetchResults = managedContext.executeFetchRequest(fetchRequest, error: nil) as? [NSManagedObject] {
       if fetchResults.count != 0{

            // Will only be one photo with this photo id
            var photo = fetchResults[0]

            photo.setValue(true, forKey: "toDelete")

            // Save the object
            var error: NSError?
            if !managedContext.save(&error) {
                println("Could not save \(error), \(error?.userInfo)")
            }
        }
    }



    // Reload from core data
    self.loadPhotoSheetFromCoreData()
}

Затем self.loadPhotoSheetFromCoreData() очищает progressPhotoSheet.progressPhotos перед получением новых данных из базовых данных... Код ниже...

private func loadPhotoSheetFromCoreData() {

    if(self.hasPhotoSheet()) {

        // Clear existing photos
        self.progressPhotos = []

        // Set up Core Data Managed Object Context
        let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
        let managedContext = appDelegate.managedObjectContext!

        let request = NSFetchRequest(entityName: "CDProgressPhoto")
        let predicate1 = NSPredicate(format: "photoSheetId == %@", String(self.sheetId))
        let predicate2 = NSPredicate(format: "toDelete == %@", false)
        request.sortDescriptors = [NSSortDescriptor(key: "date", ascending: false) as NSSortDescriptor]
        var predicatesArray: [NSPredicate] = [predicate1, predicate2]
        //predicatesArray.append(predicate1)
        request.predicate = NSCompoundPredicate.andPredicateWithSubpredicates(predicatesArray)
        let existings = managedContext.executeFetchRequest(request, error: nil)
        let existingPhotos: [CDProgressPhoto] =  existings as! [CDProgressPhoto]

        // for each photo make a ProgressPhoto object and add to progress photos array
        for photo in existingPhotos {
            var newPhoto: ProgressPhoto = ProgressPhoto()
            newPhoto.photoSheetId = Int(photo.photoSheetId)
            newPhoto.photoId  = Int(photo.photoId)
            newPhoto.photoName  = photo.photoName
            newPhoto.date = Int(photo.date)
            newPhoto.url = photo.url
            newPhoto.filename = photo.filename
            newPhoto.height = Float(photo.height)
            newPhoto.width = Float(photo.width)
            newPhoto.selected = false

            self.progressPhotos.append(newPhoto)
        }

    }
}

Как вы можете видеть, что фотография на самом деле не удаляется в этот момент, я просто устанавливаю флаг toDelete на true, а затем перезагружаю только те элементы, для которых toDelete имеет значение false. Фотографии удаляются позже асинхронно в зависимости от сетевого подключения и т. Д., Поскольку они также хранятся на сервере для использования на основном веб-сайте.

1 ответ

Вы пытались вызвать invalidateLayout() для collectionView? Это может помочь, если ваше представление пусто, т. Е. Присутствует 0 элементов.

Другие вопросы по тегам