从 UICollectionViewController 删除单元格的问题
Posted
技术标签:
【中文标题】从 UICollectionViewController 删除单元格的问题【英文标题】:Issue deleting cells from UICollectionViewController 【发布时间】:2018-06-01 19:00:28 【问题描述】:我正在使用 UICollectionViewController,我正在尝试在所选项目的循环中使用 deleteItems,如下所示:
for item in (collectionView?.indexPathsForSelectedItems)!
let cell = self.collectionView?.cellForItem(at: item) as! ImageCollectionCell
deleteLandGradingImage(images: ImagesData(jobNo: self.jobNo, ImageBytes: (self.array[item.item]["imageBytes"] as! String), Username: appDelegate.username)) result in
cell.imageView.layer.borderWidth = 0
self.navigationItem.rightBarButtonItems = [self.editButton]
self.editButton.isEnabled = true
self.editButton.title = "Edit"
self.doneButton.title = "Done"
self.array.remove(at: item.item)
self.collectionView?.deselectItem(at: item, animated: true)
self.collectionView?.deleteItems(at: [item])
deleteLandGradingImage(images: ImagesData(jobNo: self.jobNo, ImageBytes: (self.array[item.item]["imageBytes"] as! String), Username: appDelegate.username)) result in
是对删除单元格内的图像并将其从数据库中删除的 API 的调用。
func deleteLandGradingImage(images: ImagesData, completionHandler:@escaping (_ result:Bool) -> Void)
//Define array for returning data
var returnedResults = Bool()
//Call API
WebService().deleteLandGradingImages(images: images)
(result: Bool) in
DispatchQueue.main.async
//Return our results
returnedResults = result
completionHandler(returnedResults)
这是WebService中的方法:
func deleteLandGradingImages(images: ImagesData, completion: @escaping (_ result: Bool) -> Void)
var jsonDict = [AnyHashable: Any]()
//Set Lot
jsonDict["jobNo"] = images.jobNo
//Set Image
jsonDict["imageBytes"] = images.ImageBytes
let jsonData: Data? = try? JSONSerialization.data(withJSONObject: jsonDict, options: .prettyPrinted)
let urlComponents = NSURLComponents(string: webservice + "DeleteGradingImages");
//Assign Username
urlComponents?.user = appDelegate.username;
//Assign Password
urlComponents?.password = appDelegate.password;
//Define our URL String
let url = urlComponents?.url;
//Define URL Request
var request = URLRequest(url: url!)
//Set Header Values for request
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
//Set Header Values for request
request.setValue("application/json", forHTTPHeaderField: "Accept")
//Set Request Method to POST
request.httpMethod = "POST"
//Set Request Body to JSON Data
request.httpBody = jsonData
Alamofire.request(request)
.responseJSON response in
if(response.error != nil)
completion(false)
else
let responseString = (String(data: response.data!, encoding: .utf8) != nil) as Bool
completion(responseString)
我的循环问题是有时它可以工作,有时我会收到这个错误:
无效更新:第 0 节中的项目数无效。 更新 (1) 后包含在现有部分中的项目必须是 等于该部分中包含的项目数之前 update (1),加上或减去插入或删除的项目数 该部分(0 插入,1 删除)和加或减的数量 移入或移出该部分的项目(0 移入,0 移出)。
有时我会收到此错误:
线程 1:致命错误:索引超出范围
在这条线上
self.array.remove(at: item.item)
我做错了什么?
更新
我从一个答案中得到了这个:
@IBAction func deleteButtonPressed(_ sender: Any)
let group = DispatchGroup()
let indexPaths = (collectionView?.indexPathsForSelectedItems)!
var deletes = Array<Dictionary<String, Any>>()
for item in indexPaths
deletes.append(self.array[item.item])
for item in deletes
group.enter()
deleteLandGradingImage(images: ImagesData(jobNo: self.jobNo, ImageBytes: (item["imageBytes"] as! String), Username: appDelegate.username)) result in
let i = self.array.index (dic) -> Bool in
return true
if i != nil
self.array.remove(at: i!)
group.leave()
group.notify(queue: .main)
for item in indexPaths
let cell = self.collectionView?.cellForItem(at: item) as! ImageCollectionCell
cell.imageView.layer.borderWidth = 0
self.collectionView?.deselectItem(at: item, animated: true)
self.navigationItem.rightBarButtonItems = [self.editButton]
self.editButton.isEnabled = true
self.editButton.title = "Edit"
self.doneButton.title = "Done"
self.collectionView?.deleteItems(at: indexPaths)
if(self.array.count == 0)
self.imageCollectionDelegate?.ImageCollectionChange(false)
但有时我会在这一行出现错误:
let cell = self.collectionView?.cellForItem(at: item) as! ImageCollectionCell
这是错误:
线程 1:致命错误:打开包装时意外发现 nil 可选值
我注意到这只发生在 iPhone 上,如果我选择图像并滚动 UICollectionView,然后单击删除按钮。
更新
我也试过这个:
@IBAction func deleteButtonPressed(_ sender: Any)
self.createIndicator()
for item in (collectionView?.indexPathsForSelectedItems)!
if let cell = self.collectionView?.cellForItem(at: item) as! ImageCollectionCell?
deleteLandGradingImage(images: ImagesData(jobNo: self.jobNo, ImageBytes: (self.array[item.item]["imageBytes"] as! String), Username: appDelegate.username)) result in
cell.imageView.layer.borderWidth = 0
self.collectionView?.performBatchUpdates(
self.array.remove(at: item.item)
self.collectionView?.deselectItem(at: item, animated: true)
self.collectionView?.deleteItems(at: [item])
) completed in
self.navigationItem.rightBarButtonItems = [self.editButton]
self.editButton.isEnabled = true
self.editButton.title = "Edit"
self.doneButton.title = "Done"
self.stopIndicator()
但我收到此错误:
线程 1:致命错误:索引超出范围
在这一行:
self.array.remove(at: item.item)
【问题讨论】:
评论您的更新:self.array.remove(at: item.item)
正在为您崩溃,所以您能否在执行删除操作之前打印您的数组,并在其下方打印 item.item,您收到错误,因为 item 是您正在尝试删除的不是您的数组中的退出(数组的元素较少)
【参考方案1】:
有两个问题:
-
在使用
collectionView?.indexPathsForSelectedItems
的循环中更新collectionView
打电话给collectionView?.deleteItems(at: [item])
太频繁了
最好的选择是对所有索引执行网络请求,然后一步将它们从 collectionView 中删除。您可以将请求与DispatchGroup
合并到一个链中。
一些解释:删除两个项目。 1 和 2。有时会先删除 1,然后 indexPathsForSelectedItems
将只包含一个索引 (1)。但是循环会尝试删除 indexPath 2 处的项目。这是一个崩溃。
在您的代码中使用 DispatchGroup 的示例:
let group = DispatchGroup()
let indexPaths = (collectionView?.indexPathsForSelectedItems)!
var deletes = [<your type>]()
for item in indexPaths
deletes.append(array[item.item])
// TODO: Block UI with UIActivityIndicatorView
for item in deletes
group.enter()
deleteLandGradingImage(images: ImagesData(jobNo: self.jobNo, ImageBytes: (item["imageBytes"] as! String), Username: appDelegate.username)) result in
let i = self.array.index(of: item)!
self.array.remove(at: i)
group.leave()
group.notify(queue: .main)
self.navigationItem.rightBarButtonItems = [self.editButton]
self.editButton.isEnabled = true
self.editButton.title = "Edit"
self.doneButton.title = "Done"
self.collectionView?.deleteItems(at: indexPaths)
【讨论】:
我可以使用我的代码获取 DispatchGroup 的示例吗? 这里出现错误:let cell = self.collectionView?.cellForItem(at: item) as! ImageCollectionCell 线程 1:致命错误:在展开可选值时意外发现 nil 如果删除for item in indexPaths let cell = self.collectionView?.cellForItem(at: item) as! ImageCollectionCell cell.imageView.layer.borderWidth = 0 self.collectionView?.deselectItem(at: item, animated: true)
会怎样?
我现在试试【参考方案2】:
如果你得到错误
部分中的项目数无效
因为,随着任何集合的变化,它希望拥有与源数组相同数量的项目,您可以使用 performBatchUpdates
来解决这个问题:
for item in (collectionView?.indexPathsForSelectedItems)!
if let cell = self.collectionView?.cellForItem(at: item) as? ImageCollectionCell
deleteLandGradingImage(images: ImagesData(jobNo: self.jobNo, ImageBytes: (self.array[item.item]["imageBytes"] as! String), Username: appDelegate.username)) result in
cell.imageView.layer.borderWidth = 0
collectionView?.performBatchUpdates(
self.array.remove(at: item.item)
self.collectionView?.deselectItem(at: item, animated: true)
self.collectionView?.deleteItems(at: [item])
) completed in
self.navigationItem.rightBarButtonItems = [self.editButton]
self.editButton.isEnabled = true
self.editButton.title = "Edit"
self.doneButton.title = "Done"
【讨论】:
我想把这段代码放在哪里?替换我的删除按钮中的所有内容? 您的代码出现此错误:条件绑定的初始化程序必须具有可选类型,而不是此行上的“ImageCollectionCell”:if let cell = self.collectionView?.cellForItem(at: item) as! ImageCollectionCell 我修复了这个:可选类型,而不是 'ImageCollectionCell' 如果让 cell = self.collectionView?.cellForItem(at: item) as!图像收集单元? 但是当我运行代码时出现新错误:线程 1:致命错误:此行的索引超出范围 self.array.remove(at: item.item) 仍然遇到同样的错误:线程 1:致命错误:self.array.remove(at:item.item) 上的索引超出范围【参考方案3】:正如上面所有答案所说 - 您需要使用 performBatchUpdates
方法进行 UICollectionView 更新。
来自文档:
您可以在想要制作多个的情况下使用此方法 在一个动画操作中更改集合视图,如 反对在几个单独的动画中。你可以使用这个方法 插入、删除、重新加载或移动单元格或使用它来更改 与一个或多个单元格相关的布局参数。使用块 传入更新参数以指定您的所有操作 想表演。
这只是意味着您需要在performBatchUpdates
闭包内一次性删除所有项目。
您可以使用此代码来执行此操作:
var indexes: [IndexPath] = []
for item in (collectionView?.indexPathsForSelectedItems)!
if let cell = self.collectionView?.cellForItem(at: item) as? ImageCollectionCell
deleteLandGradingImage(images: ImagesData(jobNo: self.jobNo, ImageBytes: (self.array[item.item]["imageBytes"] as! String), Username: appDelegate.username)) result in
cell.imageView.layer.borderWidth = 0
self.collectionView?.deselectItem(at: item, animated: true)
indexes.append(item.item)
indexes.forEach self.array.remove(at: $0)
collectionView?.performBatchUpdates(
self.collectionView?.deleteItems(at: [indexes])
) completed in
self.navigationItem.rightBarButtonItems = [self.editButton]
self.editButton.isEnabled = true
self.editButton.title = "Edit"
self.doneButton.title = "Done"
【讨论】:
【参考方案4】:我认为您应该首先从数组中删除项目而不是更新数据库我的项目有类似的问题,这个简单的更改解决了这个问题。我回家后尝试发布一些代码。希望这会有所帮助。
【讨论】:
以上是关于从 UICollectionViewController 删除单元格的问题的主要内容,如果未能解决你的问题,请参考以下文章