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

use*_*331 6 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
}
Run Code Online (Sandbox Code Playgroud)

是对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)

            }

        }

    }
Run Code Online (Sandbox Code Playgroud)

这是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)
                }

        }
    }
Run Code Online (Sandbox Code Playgroud)

我的循环问题是,有时它有效,有时我得到这个错误:

更新无效:第0部分中的项目数无效.更新(1)后现有部分中包含的项目数必须等于更新前该部分中包含的项目数(1),加上或减去数字从该部分插入或删除的项目(0已插入,1已删除)以及加或减移入或移出该部分的项目数量(0移入,0移出).

有时我会收到此错误:

线程1:致命错误:索引超出范围

在这条线上

self.array.remove(at: item.item)
Run Code Online (Sandbox Code Playgroud)

我究竟做错了什么?

UPDATE

我从答案中得到了这个:

@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)
            }

        }

    }
Run Code Online (Sandbox Code Playgroud)

但有时我会在这一行上收到错误:

let cell = self.collectionView?.cellForItem(at: item) as! ImageCollectionCell
Run Code Online (Sandbox Code Playgroud)

这是错误:

线程1:致命错误:在解开Optional值时意外发现nil

我注意到这只发生在iPhone上,如果我选择图像并滚动浏览UICollectionView,则单击删除按钮.

UPDATE

我也试过这个:

@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()

                    }
                }
            }
        }

    }
Run Code Online (Sandbox Code Playgroud)

但我得到这个错误:

线程1:致命错误:索引超出范围

在这一行:

self.array.remove(at: item.item)
Run Code Online (Sandbox Code Playgroud)

llk*_*nny 3

有两个问题:

  1. 在循环中更新 collectionView 使用collectionView?.indexPathsForSelectedItems
  2. 打电话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)
}
Run Code Online (Sandbox Code Playgroud)