从UICollectionViewController发出删除单元格的问题

时间:2018-06-01 19:00:29

标签: ios swift

我正在使用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)后现有部分中包含的项目必须是   等于该部分之前包含的项目数   更新(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)

4 个答案:

答案 0 :(得分:3)

有两个问题:

  1. 使用collectionView?.indexPathsForSelectedItems
  2. 更新循环中的collectionView
  3. 经常致电collectionView?.deleteItems(at: [item])
  4. 最佳选择是对所有索引执行网络请求,然后一步从collectionView中删除它们。您可以将一个链中的请求与DispatchGroup组合在一起。

    一些解释:删除两个项目。有时1将首先删除,之后indexPathsForSelectedItems将只包含一个索引(1)。但是loop会尝试删除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)
    }
    

答案 1 :(得分:0)

如果您收到错误

  

部分中的项目数无效

因为,在任何集合更改的情况下,它希望具有与其源数组相同数量的项目,您可以使用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"

            }
        }
    }
}

答案 2 :(得分:0)

如上所述,您需要使用performBatchUpdates方法进行UICollectionView更新。

来自文档:

  

您可以在想要制作多个的情况下使用此方法   在一个动画操作中更改为集合视图,如   反对几个单独的动画。您可以使用此方法   插入,删除,重新加载或移动单元格或使用它来更改单元格   与一个或多个单元格关联的布局参数。使用块   传递了updates参数以指定您的所有操作   想要表演。

这只是意味着您需要在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"
}

答案 3 :(得分:0)

我相信你应该首先从数组中删除项目而不是更新数据库我的项目有类似的问题,这个简单的更改解决了这个问题。我回家后尝试发布一些代码。希望这会有所帮助。