NSFetchedResultsController 在错误的 indexPath 中添加项目
NSFetchedResultsController adds item in wrong indexPath
我编写了简单的计数器应用程序。它使用 CoreData 来存储数据。在模型中,我有一个名为 "Counter" 的实体,其属性为 "value" (Int64) 和 "position"(Int16)。第二个属性是在 tableView 中的位置。用户可以添加、删除或增加计数器。我还使用 NSFetchedResultsController 来填充我的 tableView。应用程序可以运行,但是当我添加 5 个计数器、更改它们的值、删除第二个和第三个值并添加一个新值时,计数器将不会插入到 tableView 的末尾(这里是视频 https://youtu.be/XXyuEaobd3c) .我的代码有什么问题?
import UIKit
import CoreData
class TableViewController: UITableViewController, NSFetchedResultsControllerDelegate {
let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
var frc: NSFetchedResultsController<Counter> = {
let fetchRequest: NSFetchRequest<Counter> = Counter.fetchRequest()
let sortDescriptor = NSSortDescriptor(key: "position", ascending: true)
fetchRequest.sortDescriptors = [sortDescriptor]
let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
let frc = NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext: context, sectionNameKeyPath: nil, cacheName: nil)
do {
try frc.performFetch()
} catch {
print(error)
}
return frc
}()
@IBAction func addCounter(_ sender: UIBarButtonItem) {
let counter = Counter(context: context)
counter.value = 0
counter.position = Int16(frc.fetchedObjects!.count)
do {
try context.save()
} catch {
print(error)
}
}
@IBAction func longPressed(_ sender: UILongPressGestureRecognizer) {
if sender.state == UIGestureRecognizerState.began {
let touchPoint = sender.location(in: self.view)
if let indexPath = tableView.indexPathForRow(at: touchPoint) {
// your code here, get the row for the indexPath or do whatever you want
let counter = frc.object(at: indexPath)
counter.value = 0
do {
try context.save()
} catch {
print(error)
}
}
}
}
override func viewDidLoad() {
super.viewDidLoad()
frc.delegate = self
}
// MARK: - Table view data source
override func numberOfSections(in tableView: UITableView) -> Int {
guard let sections = frc.sections?.count else {return 0}
return sections
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
guard let sections = frc.sections else {return 0}
return sections[section].numberOfObjects
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
let counter = frc.object(at: indexPath)
cell.textLabel!.text! = String(counter.value)
return cell
}
func controllerWillChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) {
tableView.beginUpdates()
}
func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>, didChange anObject: Any, at indexPath: IndexPath?, for type: NSFetchedResultsChangeType, newIndexPath: IndexPath?) {
switch type {
case .insert:
guard let indexPath = newIndexPath else {return}
tableView.insertRows(at: [indexPath], with: .fade)
case .delete:
guard let indexPath = indexPath else {return}
tableView.deleteRows(at: [indexPath], with: .fade)
case .update:
guard let indexPath = indexPath else {return}
let cell = tableView.cellForRow(at: indexPath)
let counter = frc.object(at: indexPath)
cell?.textLabel?.text = String(counter.value)
default:
break
}
}
func controllerDidChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) {
tableView.endUpdates()
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let counter = frc.object(at: indexPath)
counter.value += Int64(1)
do {try context.save()}
catch {print(error)}
tableView.deselectRow(at: indexPath, animated: true)
}
// Override to support editing the table view.
override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
if editingStyle == .delete {
let counter = frc.object(at: indexPath)
context.delete(counter)
do {
try context.save()
} catch {
print(error)
}
}
}
}
您添加位置的方式有误。
假设您有
A1、A2、A3、A4、A5
然后删除A2,A3
在那之后你有
A1、A4、A5
所以添加新的是B3,因为现在计数是3
A1、B3、A4、A5
添加另一行成为 B4,因此它可以在 A4 之前或之后的任何位置。
这个顺序是根据位置排序的。
您可以解决这个问题,方法是获取最后获取的对象并增加位置,结果将是:
A1、A4、A5、B6、B7
我编写了简单的计数器应用程序。它使用 CoreData 来存储数据。在模型中,我有一个名为 "Counter" 的实体,其属性为 "value" (Int64) 和 "position"(Int16)。第二个属性是在 tableView 中的位置。用户可以添加、删除或增加计数器。我还使用 NSFetchedResultsController 来填充我的 tableView。应用程序可以运行,但是当我添加 5 个计数器、更改它们的值、删除第二个和第三个值并添加一个新值时,计数器将不会插入到 tableView 的末尾(这里是视频 https://youtu.be/XXyuEaobd3c) .我的代码有什么问题?
import UIKit
import CoreData
class TableViewController: UITableViewController, NSFetchedResultsControllerDelegate {
let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
var frc: NSFetchedResultsController<Counter> = {
let fetchRequest: NSFetchRequest<Counter> = Counter.fetchRequest()
let sortDescriptor = NSSortDescriptor(key: "position", ascending: true)
fetchRequest.sortDescriptors = [sortDescriptor]
let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
let frc = NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext: context, sectionNameKeyPath: nil, cacheName: nil)
do {
try frc.performFetch()
} catch {
print(error)
}
return frc
}()
@IBAction func addCounter(_ sender: UIBarButtonItem) {
let counter = Counter(context: context)
counter.value = 0
counter.position = Int16(frc.fetchedObjects!.count)
do {
try context.save()
} catch {
print(error)
}
}
@IBAction func longPressed(_ sender: UILongPressGestureRecognizer) {
if sender.state == UIGestureRecognizerState.began {
let touchPoint = sender.location(in: self.view)
if let indexPath = tableView.indexPathForRow(at: touchPoint) {
// your code here, get the row for the indexPath or do whatever you want
let counter = frc.object(at: indexPath)
counter.value = 0
do {
try context.save()
} catch {
print(error)
}
}
}
}
override func viewDidLoad() {
super.viewDidLoad()
frc.delegate = self
}
// MARK: - Table view data source
override func numberOfSections(in tableView: UITableView) -> Int {
guard let sections = frc.sections?.count else {return 0}
return sections
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
guard let sections = frc.sections else {return 0}
return sections[section].numberOfObjects
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
let counter = frc.object(at: indexPath)
cell.textLabel!.text! = String(counter.value)
return cell
}
func controllerWillChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) {
tableView.beginUpdates()
}
func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>, didChange anObject: Any, at indexPath: IndexPath?, for type: NSFetchedResultsChangeType, newIndexPath: IndexPath?) {
switch type {
case .insert:
guard let indexPath = newIndexPath else {return}
tableView.insertRows(at: [indexPath], with: .fade)
case .delete:
guard let indexPath = indexPath else {return}
tableView.deleteRows(at: [indexPath], with: .fade)
case .update:
guard let indexPath = indexPath else {return}
let cell = tableView.cellForRow(at: indexPath)
let counter = frc.object(at: indexPath)
cell?.textLabel?.text = String(counter.value)
default:
break
}
}
func controllerDidChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) {
tableView.endUpdates()
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let counter = frc.object(at: indexPath)
counter.value += Int64(1)
do {try context.save()}
catch {print(error)}
tableView.deselectRow(at: indexPath, animated: true)
}
// Override to support editing the table view.
override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
if editingStyle == .delete {
let counter = frc.object(at: indexPath)
context.delete(counter)
do {
try context.save()
} catch {
print(error)
}
}
}
}
您添加位置的方式有误。 假设您有
A1、A2、A3、A4、A5
然后删除A2,A3
在那之后你有 A1、A4、A5
所以添加新的是B3,因为现在计数是3 A1、B3、A4、A5
添加另一行成为 B4,因此它可以在 A4 之前或之后的任何位置。
这个顺序是根据位置排序的。
您可以解决这个问题,方法是获取最后获取的对象并增加位置,结果将是:
A1、A4、A5、B6、B7