如何在 swift 中使用 fetchedresultscontroller 重新排序 tableview 行?

Posted

技术标签:

【中文标题】如何在 swift 中使用 fetchedresultscontroller 重新排序 tableview 行?【英文标题】:How do I reorder tableview rows using fetchedresultscontroller in swift? 【发布时间】:2015-10-07 09:21:20 【问题描述】:

我正在尝试使用核心数据和 nsfetchresultscontroller 重新排序表格视图中的单元格。我发现了一些使用 Objective C 的方法(我对此一无所知)并尝试快速实现它们,这就是我想出的:

var books: Array<AnyObject> = []

// Override to support rearranging the table view.
override func tableView(tableView: UITableView, moveRowAtIndexPath fromIndexPath: NSIndexPath, toIndexPath: NSIndexPath) 

    books = fetchedResultsController.fetchedObjects!

    let book = fetchedResultsController.objectAtIndexPath(fromIndexPath)

    self.fetchedResultsController.delegate = nil

    books.removeAtIndex(fromIndexPath.row)
    books.insert(book, atIndex: toIndexPath.row)

    var i = 0
    for book in books 
        book.setValue(i++, forKey: "position")
    

    try! context.save()

    self.fetchedResultsController.delegate = self


委托和上下文引用在另一个文件的扩展中。 使用此代码有时可以工作,有时不能。我更改了顺序,再次运行应用程序,它的顺序完全不同,我无法弄清楚。尤其是当我一次移动不止一排时。如果我将每个对象的“位置”属性打印到控制台,我可以看到它们确实没有正确更新。但为什么不呢?

我做错了什么?什么是更好的选择?

提前致谢,

丹尼尔


编辑:

好的,下面是工作代码:

func initializeFetchedResultsController() 
    let request = NSFetchRequest(entityName: "Book")
    let sortDescriptor = NSSortDescriptor(key: "position", ascending: true)
    request.sortDescriptors = [sortDescriptor]

    self.fetchedResultsController = NSFetchedResultsController(fetchRequest: request, managedObjectContext: context, sectionNameKeyPath: nil, cacheName: nil)
    self.fetchedResultsController.delegate = self

    do 
        try self.fetchedResultsController.performFetch()
     catch 
        fatalError("Failed to initialize FetchedResultsController: \(error)")
    


// Override to support rearranging the table view.
override func tableView(tableView: UITableView, moveRowAtIndexPath fromIndexPath: NSIndexPath, toIndexPath: NSIndexPath) 

    initializeFetchedResultsController()
    var objects = self.fetchedResultsController.fetchedObjects! as! [ObjectClass]

    self.fetchedResultsController.delegate = nil

    let object = objects[fromIndexPath.row]
    objects.removeAtIndex(fromIndexPath.row)
    objects.insert(object, atIndex: toIndexPath.row)

    var i = 0
    for object in objects 
        object.position = i++
    

    try! context.save()

    self.fetchedResultsController.delegate = self

诀窍是 initializeFetchedResultsController 函数,除了在 viewDidLoad 中,我有它,必须在 moveRowAtIndexPath 位内重复。此外,初始化函数和数组声明都必须在将 FRC 委托设置为 nil 之前(很明显,但很容易错过)。

【问题讨论】:

【参考方案1】:

你不应该编辑books,它不属于你,实际上是私人数据。相反,您应该只更新正在移动的对象以更改 position 值。如果您按照当前逻辑使用数组重新排序来执行此操作,您应该创建 FRC 提供的数组的新可变副本。您还应该将位置的新值设置为 NSNumber 实例。

【讨论】:

嗯,我以为它已经是可变副本了。那我该怎么做呢?对不起,愚蠢的问题,这是我第一次尝试编程。 从文档中并不完全清楚,在 obj-c 中它是不可变的,在 swift 中它很可能是您可以编辑的副本。可能NSNumber 部分是问题所在。 那么,我应该只使用“i as NSNumber”吗?我试过了,xcode没有抱怨,但它仍然不起作用。 :( 我正在考虑如何更新正在移动的对象,就像你说的那样。问题是,当我删除和对象时,我必须将其后的每个对象的位置减少一个,而且我不知道如果没有数组该怎么做...... 数组应该没问题,调试以检查循环期间将哪些数字更新到托管对象中【参考方案2】:

您需要使用 sortDescriptor,然后您从 fetch 请求返回的信息已经排序。这就是我实现 fetchRequests 的方式:

lazy var connectionsFetchRequest: NSFetchRequest = 
   var request = NSFetchRequest(entityName: "Connection")
    let predicate = NSPredicate(format: "%K == %@", argumentArray: ["user", UserManager.SharedInstance.user!])
    request.sortDescriptors = [NSSortDescriptor(key: "firstName", ascending: true)]
    request.predicate = predicate
    return request
()

【讨论】:

我正在这样做……我会用代码更新问题。 请显示更多代码。我们需要知道你已经在做什么。请发布您的 fetchRequest。

以上是关于如何在 swift 中使用 fetchedresultscontroller 重新排序 tableview 行?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 kotlin native 中使用 swift 库?

如何在 Swift 中使用 Apple 地图 - 你必须使用 C 还是 Swift 可以?

如何在 Swift 中使用 MKPolylineView

如何在 Swift 中使用`syslog`

如何在 swift 项目中使用 TPKeyboardAvoiding?

如何在 Playground 中使用 Swift 包管理器