У меня есть TableVIew
, который заполняется FetchResultsController
.Выбранные элементы правильно отображаются в своем собственном разделе, но я хочу показать только один раз тот же тип объекта, но сохранить количество выбранных объектов.Пример: имя объекта: Item
, атрибут объекта: itemId: String
, category: String
.category
используется для сортировки выборки и создания Tableview
разделов.Поэтому, если бы у меня было три ячейки для одного и того же itemId
извлеченного объекта, я просто хочу отобразить одну ячейку и вести подсчет того, сколько их должно было отображаться, и отображать его в метке в единственной отображаемой ячейке.Я пытаюсь использовать itemFetchRequest.propertiesToFetch = ["itemId"]
и itemFetchRequest.returnsDistinctResults = true
, которые должны удалить все дубликаты на основе атрибута itemId
объекта Item
, но я все еще получаю более одной ячейки с одинаковыми элементами.Вы можете определить, почему itemFetchController
возвращает кратные значения одного и того же элемента?
Это код, который я создал до сих пор 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 я получаю Thread 1: Fatal error: NSArray element failed to match the Swift Array Element type
на линии let item = itemFetchedResultController!.fetchedObjects![indexPath.row]
.Преобразование в NSArray
не решило проблему.Есть идеи по этому поводу?
В версии 2 вместо этого я получаю *** 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
}