Почему 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 элементов.