根据对象参数UPDATED Swift从提取中删除重复的对象 [英] Removing duplicate objects from fetch based on object parameter UPDATED Swift

查看:54
本文介绍了根据对象参数UPDATED Swift从提取中删除重复的对象的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个TableVIew,由FetchResultsController填充.获取的项目正确显示在其各自的部分中,但是我要实现的是仅显示一次相同类型的对象,但存储已获取的对象的数量. 示例:实体名称:Item,实体属性:itemId: Stringcategory: String. category用于对访存进行排序并创建Tableview节.因此,如果对于相同的itemId提取对象有三个单元格,我只想显示一个单元格并保留应该显示的单元格数,并在唯一显示的单元格中的标签中显示它. 我正在尝试使用itemFetchRequest.propertiesToFetch = ["itemId"]itemFetchRequest.returnsDistinctResults = true来消除基于Item实体的itemId属性的所有重复项,但是我仍然得到多个具有相同项目的单元格. 您能发现为什么itemFetchController返回相同项目的倍数吗?

I have a TableVIewthat gets populated by a FetchResultsController. Fetched items are properly displayed in their own section but what I want to achieve is to show only once the same type of object but store the number of objects that has been fetched. Example: Entity name: Item, entity attribute: itemId: String, category: String. category is used to sort the fetch and create Tableviewsections. So if I had three cell for the same itemId fetched object I just want to display one cell and keep count of how many they were supposed to be displayed, and display it in a label in the only displayed cell. I'm trying to use itemFetchRequest.propertiesToFetch = ["itemId"]and itemFetchRequest.returnsDistinctResults = truethat should eliminate all duplicates based on itemId attribute of Item entity but I still get more than one cell with the same items. Can you spot why itemFetchController is returning multiples of the same item?

这是我到目前为止提出的代码 cellForRowAt:

This is the code I came up with so far cellForRowAt:

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

    let cell = tableView.dequeueReusableCell(withIdentifier: "statisticsCell", for: indexPath) as! StatisticsTableViewCell
    let productPrice: String!
    cell.idInfoLabel.text = itemFetchedResultController?.object(at: indexPath).itemId!
    cell.nameInfoLabel.text = itemFetchedResultController?.object(at: indexPath).itemName!
    // get items details(image, price, minimum stock quantity) from Product Entity
    let item = itemFetchedResultController?.object(at: indexPath).itemName!
        let productRequest: NSFetchRequest<Product> = Product.fetchRequest()
        productRequest.sortDescriptors = [NSSortDescriptor(key: "name", ascending: true)]
    productRequest.predicate = NSPredicate(format: "name == %@", item!)
        productRequest.fetchLimit = 1
        do {
            let fetch = try context.fetch(productRequest)
            cell.productImageView.image = UIImage(data: (fetch[0].productImage! as Data))
            cell.minimumStockInfoLabel.text = fetch[0].minimumStock
            productPrice = fetch[0].price

            //fetch itemes for amount of single object
            let itemId = itemFetchedResultController?.object(at: indexPath).itemId!

            print(itemId!)
            let itemRequest = NSFetchRequest<Item>(entityName: "Item")
            itemRequest.sortDescriptors = [NSSortDescriptor(key: "itemName", ascending: true)]
            itemRequest.predicate = NSPredicate(format: "date BEGINSWITH %@", dateToFetchMin)
            itemRequest.predicate = NSPredicate(format: "itemId == %@", itemId!)
            do {
                let itemFetch = try context.fetch(itemRequest)
                print(productPrice)
                print(itemFetch, itemFetch.count)
                cell.soldQuantityInfoLabel.text = String(describing: itemFetch.count)
                let amount = Double(productPrice!)! * Double(itemFetch.count)
                cell.salesAmountInfoLabel.text = String(describing: amount)
            } catch  {
                print("Error in fetching sold items for cell: \(error)")
            }
        } catch  {
            print("Error in fetching product for cell: \(error)")
        }
    return cell
}

FetchResultController:

var itemFetchedResultController: NSFetchedResultsController<Item>?

和获取功能:

func configureItemFetchedResultsController() {
        print("configureItemFetchedResultsController(): started")

        // first sortDescriptor filters the date range:  possibly change date from String to dates in both function and  CoreData and use "(date >= %@) AND (date <= %@)" instead of "BEGINSWITH" in predicate
        let itemFetchRequest = NSFetchRequest<Item>(entityName: "Item")
        itemFetchRequest.sortDescriptors = [NSSortDescriptor(key: "category", ascending: true),NSSortDescriptor(key: "itemId", ascending: true)]
        itemFetchRequest.predicate = NSPredicate(format: "order.user.name == %@", UserDetails.fullName ?? "")
        itemFetchRequest.predicate = NSPredicate(format: "date BEGINSWITH %@", dateToFetchMin)
        itemFetchRequest.propertiesToFetch = ["itemId"]
        itemFetchRequest.returnsDistinctResults = true
        //        itemFetchRequest.propertiesToGroupBy = ["category","itemId","itemName"]
        //        itemFetchRequest.resultType = .dictionaryResultType
        itemFetchedResultController = NSFetchedResultsController(fetchRequest: itemFetchRequest, managedObjectContext: context, sectionNameKeyPath: "category", cacheName: nil)
        do {
            try itemFetchedResultController?.performFetch()
            self.statisticsTableView.reloadData()
            print("configureItemFetchedResultsController(): sold items fetched")
        } catch  {
            //            fatalError("failed to fetch entities: \(error)")
            print("configureItemFetchedResultsController(): failed to fetch Item entities: \(error)")
        }
        self.statisticsTableView.reloadData()
    }

实际TableView结果:

更新:

尝试走Dictionary路线并使用itemFetchRequest.propertiesToFetch = ["category","itemId","itemName"]itemFetchRequest.propertiesToGroupBy = ["category","itemId","itemName"]之后,我终于得到了fetch结果,我希望每个itemId只能是一个对象,但代价是无法将它们正确地分为几部分以参数category命名.我决定然后使用itemFetchResultsController返回执行提取操作,并且得到相同的提取对象,因此使用itemFetchRequest.propertiesToFetch = ["category","itemId","itemName"]itemFetchRequest.propertiesToGroupBy = ["category","itemId","itemName"]现在可以使.distinctResults正常工作. 我的问题现在在cellForRowAt中. 在版本1中,我在行let item = itemFetchedResultController!.fetchedObjects![indexPath.row]上获得了Thread 1: Fatal error: NSArray element failed to match the Swift Array Element type. 将其转换为NSArray didnt可解决该问题.有什么想法吗?

After trying to go the Dictionaryroute and using itemFetchRequest.propertiesToFetch = ["category","itemId","itemName"] and itemFetchRequest.propertiesToGroupBy = ["category","itemId","itemName"] I finally got the fetch result I wanted being only one object per itemId, at cost of not having them properly divided into sections named after the parameter category. I decided then to go back using itemFetchResultsControllerto perform the fetch and I get the same fetched objects so using itemFetchRequest.propertiesToFetch = ["category","itemId","itemName"] and itemFetchRequest.propertiesToGroupBy = ["category","itemId","itemName"] makes now .distinctResults work. My problem now is in cellForRowAt. In version1 I get Thread 1: Fatal error: NSArray element failed to match the Swift Array Element typeon the line let item = itemFetchedResultController!.fetchedObjects![indexPath.row]. Casting it as NSArraydidnt solve it. Any ideas on this?

在version2中,我得到的是*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[NSKnownKeysDictionary1 itemName]: unrecognized selector sent to instance 0x60000078a2e0'.

In version2 instead I get *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[NSKnownKeysDictionary1 itemName]: unrecognized selector sent to instance 0x60000078a2e0'.

所以新代码是:

FetchResultController:

func configureItemFetchedResultsController() {
        print("configureItemFetchedResultsController(): started")
        let itemFetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: "Item")
        itemFetchRequest.sortDescriptors = [NSSortDescriptor(key: "category", ascending: true),NSSortDescriptor(key: "itemId", ascending: true)]
        let user = NSPredicate(format: "order.user.name == %@", UserDetails.fullName ?? "")
        let dateFrom = Conversions.dateConvert(dateString: dateToFetchMin)!
        let dateTo = Conversions.dateConvert(dateString: dateToFetchMax)!
        print(dateFrom)
        let from = NSPredicate(format: "date >= %@", dateFrom as CVarArg)
        let to = NSPredicate(format: "date <= %@", dateTo as CVarArg)
        itemFetchRequest.predicate = NSCompoundPredicate(andPredicateWithSubpredicates: [user,from,to])
        itemFetchRequest.propertiesToFetch = ["category","itemId","itemName"]]
        itemFetchRequest.returnsDistinctResults = true
        itemFetchRequest.propertiesToGroupBy = ["category","itemId","itemName"]
        itemFetchRequest.resultType = NSFetchRequestResultType.dictionaryResultType 

        itemFetchedResultController = NSFetchedResultsController(fetchRequest: itemFetchRequest, managedObjectContext: context, sectionNameKeyPath: "category", cacheName: nil) as? NSFetchedResultsController<Item>
        do {
            try itemFetchedResultController?.performFetch()
            let resultsDict = itemFetchedResultController!.fetchedObjects!
            print(resultsDict as NSArray)
            print("configureItemFetchedResultsController(): sold items fetched")
        } catch  {
            //            fatalError("failed to fetch entities: \(error)")
            print("configureItemFetchedResultsController(): failed to fetch Item entities: \(error)")
        }
        self.statisticsTableView.reloadData()
    }

cellForRowAt版本1:

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

        let item = itemFetchedResultController!.fetchedObjects![indexPath.row] //as NSArray
        let name = item.itemName!//["itemName"]!
        let itemId = item.itemId!
//        let productPrice: String!
        let cell = tableView.dequeueReusableCell(withIdentifier: "statisticsCell", for: indexPath) as! StatisticsTableViewCell
        let productRequest: NSFetchRequest<Product> = Product.fetchRequest()
        productRequest.sortDescriptors = [NSSortDescriptor(key: "name", ascending: true)]
        productRequest.predicate = NSPredicate(format: "name == %@", name)
        productRequest.fetchLimit = 1
        do {
            let fetch = try context.fetch(productRequest)
            cell.idInfoLabel.text = fetch[0].productId
            cell.nameInfoLabel.text = fetch[0].name
            cell.productImageView.image = UIImage(data: (fetch[0].productImage! as Data))
            cell.minimumStockInfoLabel.text = fetch[0].minimumStock
            let productPrice = fetch[0].price
            //fetch itemes for amount of single object
            let itemRequest = NSFetchRequest<Item>(entityName: "Item")
            itemRequest.sortDescriptors = [NSSortDescriptor(key: "itemName", ascending: true)]
            itemRequest.predicate = NSPredicate(format: "date BEGINSWITH %@", dateToFetchMin)
            itemRequest.predicate = NSPredicate(format: "itemId == %@", itemId)
            do {
                let itemFetch = try context.fetch(itemRequest)
                print(productPrice!)
                print(itemFetch, itemFetch.count)
                cell.soldQuantityInfoLabel.text = String(describing: itemFetch.count)
                let amount = Double(productPrice!)! * Double(itemFetch.count)
                cell.salesAmountInfoLabel.text = String(describing: amount)
            } catch  {
                print("Error in fetching sold items for cell: \(error)")
            }
        } catch  {
            print("Error in fetching product for cell: \(error)")
        }
        return cell
    }

cellForRowAt版本2:

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

        let cell = tableView.dequeueReusableCell(withIdentifier: "statisticsCell", for: indexPath) as! StatisticsTableViewCell
        let item = itemFetchedResultController?.object(at: indexPath).itemName!
        //        let item = itemResultsArray[indexPath.row]
        let productRequest: NSFetchRequest<Product> = Product.fetchRequest()
        productRequest.sortDescriptors = [NSSortDescriptor(key: "name", ascending: true)]
        productRequest.predicate = NSPredicate(format: "name == %@", item!)
        productRequest.fetchLimit = 1
        do {
            let fetch = try context.fetch(productRequest)
            cell.idInfoLabel.text = fetch[0].productId
            cell.nameInfoLabel.text = fetch[0].name
            cell.productImageView.image = UIImage(data: (fetch[0].productImage! as Data))
            cell.minimumStockInfoLabel.text = fetch[0].minimumStock
            let productPrice = fetch[0].price
            //fetch item for amount of single object
            let itemId = itemFetchedResultController?.object(at: indexPath).itemId!
            let itemRequest = NSFetchRequest<Item>(entityName: "Item")
            itemRequest.sortDescriptors = [NSSortDescriptor(key: "itemName", ascending: true)]
            itemRequest.predicate = NSPredicate(format: "date BEGINSWITH %@", dateToFetchMin)
            itemRequest.predicate = NSPredicate(format: "itemId == %@", itemId!)
            do {
                let itemFetch = try context.fetch(itemRequest)
                print(productPrice!)
                print(itemFetch, itemFetch.count)
                cell.soldQuantityInfoLabel.text = String(describing: itemFetch.count)
                let amount = Double(productPrice!)! * Double(itemFetch.count)
                cell.salesAmountInfoLabel.text = String(describing: amount)
            } catch  {
                print("Error in fetching sold items for cell: \(error)")
            }
        } catch  {
            print("Error in fetching product for cell: \(error)")
        }
        return cell
    }

推荐答案

经过几天的测试,测试了不同的选项并得到了各种各样的错误,我终于纠正了代码,使其可以正常工作.在此过程中,我发现了一些基本要点(从我尝试查找问题的解决方案的职位数量来看),很多人都处于控制之下.这个答案是为了帮助其他人并阐明使不同结果起作用所必需的强制性属性和类型定义.

After a couple of days of testing different options and getting all sort of errors, I finally corrected the code to work as I wanted. During the process I found out basic points that ( judging by the quantity of posts I had a look at trying to find a solution to my problem ), very a few people got under their belts. This answer is to help others and clarify the mandatory properties and type definitions that are involved in getting distinct results to work.

分步指南:

1st:itemFetchRequest.returnsDistinctResults = true这将结果设置为不同

1st: itemFetchRequest.returnsDistinctResults = true this set the result to be distinct

2nd:itemFetchRequest.propertiesToFetch = ["category","itemId","itemName"] 这就是您要在结果中显示的属性,它们也必须位于.propertiesToGroupBy中.

2nd: itemFetchRequest.propertiesToFetch = ["category","itemId","itemName"] this is what properties you want to show in your results and they need also to be in .propertiesToGroupBy .

第3个:itemFetchRequest.propertiesToGroupBy = ["category","itemId","itemName"] 这是您想要不同结果的属性.

3rd: itemFetchRequest.propertiesToGroupBy = ["category","itemId","itemName"] this is the properties you want distinct results of.

4th:itemFetchRequest.resultType = NSFetchRequestResultType.dictionaryResultType这是唯一获得不同结果的允许类型.

4th: itemFetchRequest.resultType = NSFetchRequestResultType.dictionaryResultType this is the only allowed type to get distinct results.

5th:NSFetchedResultsController<NSDictionary>这是控制器的强制类型,否则您将无法访问获取的对象的参数值.

5th: NSFetchedResultsController<NSDictionary>this is the mandatory type for the controller as otherwise you won't have access to fetched object's parameter's values.

6th:let item = itemFetchedResultController?.object(at: indexPath)这是获取已获取对象的强制方法.使用fetchedObjects![indexPath.row]会得到错误的项目.我在两个显示的类别中都得到了相同的两项.

6th: let item = itemFetchedResultController?.object(at: indexPath) this is the mandatory way to get fetched objects. Using fetchedObjects![indexPath.row] gets wrong item. I was getting same two items in both displayed categories.

第7个:let itemName = item!["itemName"]! let itemId = item!["itemId"]!因为获取的对象是字典类型,所以这是获取参数值的方法.

7th: let itemName = item!["itemName"]! let itemId = item!["itemId"]! this is the way to get parameter's values as the fetched objects are dictionary type.

所有这些的最终代码是:

So the final code for all this is:

正在获取:

// dictionary fetch result controller
    func configureItemFetchedResultsController() {
        print("configureItemFetchedResultsController(): started")
        let itemFetchRequest = NSFetchRequest<Item>(entityName: "Item")
        itemFetchRequest.sortDescriptors = [NSSortDescriptor(key: "category", ascending: true),NSSortDescriptor(key: "itemId", ascending: true)]
        // predicates to filter for user and date range:
        let user = NSPredicate(format: "order.user.name == %@", UserDetails.fullName ?? "")
        let dateFrom = Conversions.dateConvert(dateString: dateToFetchMin)!
        let dateTo = Conversions.dateConvert(dateString: dateToFetchMax)!
        print(dateFrom)
        let from = NSPredicate(format: "date >= %@", dateFrom as CVarArg)
        let to = NSPredicate(format: "date <= %@", dateTo as CVarArg)
        itemFetchRequest.predicate = NSCompoundPredicate(andPredicateWithSubpredicates: [user,from,to])
        itemFetchRequest.returnsDistinctResults = true
        itemFetchRequest.propertiesToFetch = ["category","itemId","itemName"]//["category","itemId","itemName"]
        itemFetchRequest.propertiesToGroupBy = ["category","itemId","itemName"]
        itemFetchRequest.resultType = NSFetchRequestResultType.dictionaryResultType //.managedObjectResultType// .dictionaryResultType

        itemFetchedResultController = NSFetchedResultsController(fetchRequest: itemFetchRequest, managedObjectContext: context, sectionNameKeyPath: "category", cacheName: nil) as? NSFetchedResultsController<NSDictionary>// as! NSFetchedResultsController<Item>
        do {
            try itemFetchedResultController?.performFetch()
            print("configureItemFetchedResultsController(): sold items fetched")
        } catch  {
            //            fatalError("failed to fetch entities: \(error)")
            print("configureItemFetchedResultsController(): failed to fetch Item entities: \(error)")
        }
        self.statisticsTableView.reloadData()
    }

显示获取的对象:

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

        let cell = tableView.dequeueReusableCell(withIdentifier: "statisticsCell", for: indexPath) as! StatisticsTableViewCell
        let item = itemFetchedResultController?.object(at: indexPath)  //fetchedObjects![indexPath.row] gets the wrong item
        print("fetched is: \(String(describing: item))")
        let itemName = item!["itemName"]!
        let itemId = item!["itemId"]!
        let productRequest: NSFetchRequest<Product> = Product.fetchRequest()
        productRequest.sortDescriptors = [NSSortDescriptor(key: "name", ascending: true)]
        productRequest.predicate = NSPredicate(format: "name == %@", itemName as! CVarArg)
        productRequest.fetchLimit = 1
        do {
            let fetch = try context.fetch(productRequest)
            cell.idInfoLabel.text = fetch[0].productId
            cell.nameInfoLabel.text = fetch[0].name
            cell.productImageView.image = UIImage(data: (fetch[0].productImage! as Data))
            cell.minimumStockInfoLabel.text = fetch[0].minimumStock
            let productPrice = fetch[0].price
            //fetch itemes for amount of single object
            let itemRequest = NSFetchRequest<Item>(entityName: "Item")
            itemRequest.sortDescriptors = [NSSortDescriptor(key: "itemName", ascending: true)]
            itemRequest.predicate = NSPredicate(format: "date BEGINSWITH %@", dateToFetchMin)
            itemRequest.predicate = NSPredicate(format: "itemId == %@", itemId as! CVarArg)
            do {
                let itemFetch = try context.fetch(itemRequest)
                print(productPrice!)
                print(itemFetch, itemFetch.count)
                cell.soldQuantityInfoLabel.text = String(describing: itemFetch.count)
                let amount = Double(productPrice!)! * Double(itemFetch.count)
                cell.salesAmountInfoLabel.text = String(describing: amount)
            } catch  {
                print("Error in fetching sold items for cell: \(error)")
            }
        } catch  {
            print("Error in fetching product for cell: \(error)")
        }
        return cell
    }

非常感谢您也帮助我解决了这一问题,此日志和详细的答案是为了帮助其他人更好地理解所涉及的整个过程. 如果我的答案有问题,请发表评论,我会对其进行编辑,以免误导他人.

Many thanks for helping me out on this one as well, and this log and detailed answer is to help others understand better the whole process involved. Please comment if there is something wrong in my answer and I'll edit it, so not to mislead others with it.

这篇关于根据对象参数UPDATED Swift从提取中删除重复的对象的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆