【问题标题】:CoreData One-To-Many, sorting the manyCoreData 一对多,排序多
【发布时间】:2015-11-29 05:28:21
【问题描述】:

我正在开发一个小应用程序来学习 CoreData。这些是 CoreData 的实体。

extension Person {

    @NSManaged var firstName: String?
    @NSManaged var lastName: String?
    @NSManaged var age: NSNumber?
    @NSManaged var personToBook: NSSet?

}

extension Books {

    @NSManaged var bookName: String?
    @NSManaged var bookISBN: String?
    @NSManaged var bookToPerson: Person?

}

该应用程序是人员列表。属于列表中的每个人都可以多出一本书。

我很容易对人进行分类。

    let fetchRequest = NSFetchRequest(entityName: "Person")
    let fetchSort = NSSortDescriptor(key: "lastName", ascending: true)
    fetchRequest.sortDescriptors = [fetchSort]

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

    do {
        try fetchedResultsController.performFetch()
    }
    catch let error as NSError {
        print("Unable to perform fetch: \(error.localizedDescription)")
    }

我很难解决的是如何按字母顺序对书籍进行排序,就像我是人一样。当我点击人员列表中的一个人时,我会转到包含书籍列表的UITableView。在 prepareForSegue 中,我传入所选人员、上下文以及我在人员列表中使用的 NSFetchedResultsController

override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
    let vc = segue.destinationViewController as! BooksController

    vc.person = fetchedResultsController.objectAtIndexPath(selectedIndex) as! Person
    vc.context = self.context
    vc.fetchedResultsController = self.fetchedResultsController
}

UITableView 由 person.personToBook 填充。

override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
    return 1
}

override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return (person.personToBook?.count)!
}

override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCellWithIdentifier("BooksCell", forIndexPath: indexPath)
    let book = person.personToBook?.allObjects[indexPath.row] as! Books

    cell.textLabel?.text = book.bookName!

    return cell
}

书籍以这种方式添加到正确的人:

            let entity = NSEntityDescription.entityForName("Books", inManagedObjectContext: self.context)
            let bookInstance = Books(entity:entity!, insertIntoManagedObjectContext: self.context)

            bookInstance.bookName = alertController.textFields?[0].text
            bookInstance.bookISBN = alertController.textFields?[1].text

            self.person.mutableSetValueForKey("personToBook").addObject(bookInstance)

            do {
                try self.context.save()
                self.tableView.reloadData()
            }
            catch let error as NSError {
                print("Error saving a book \(error.localizedDescription)")
            }

personToBook 是一个 NSSet,它没有排序。我考虑过使用另一个 NSFetchedResultsController to pull the list of books out, but there is nothing unique that is identifying the books as belonging to a specific user. For instance, I could have two people with the same name of John Doe. Because of this, I'd have no way to set theNSPredicate`,这样它只会为 John Do 中的一个拉入书籍。

虽然我有一个是我可以向 Person 实体添加某种 UniqueID,就像我在 SQL 中所做的那样。这将确保我只能获得正确人的 Books 记录。有人告诉我,我不应该在 CoreData 中这样做。这使我相信必须有某种方法可以对其中的多对多部分中的项目进行排序。

我可以通过哪些方式对我的图书数据进行排序?

【问题讨论】:

  • 您是否尝试过在您的UITableView 上实现NSSortDescriptor? (设置fetchedResultsController时最好)
  • 我在 Person 实体上设置 NSSortDescriptor,因为这就是我正在做的提取。我不是在取书。当我仅通过对 Person 的获取而获取 Books 时,如何在 Books 上设置 NSSortDescriptor?
  • 怎么样:再创建一个sortDescriptor并将其添加到数组let bookNameSort = NSSortDescriptor(key: "book.bookname", ascending: true) -> fetchRequest.sortDescriptors = [fetchSort, bookNameSort]

标签: ios swift core-data


【解决方案1】:

NSSet 是无序的。该套装不会按照您添加它们的顺序返回书籍。

您可以使用以下三种不同的方法来按字母顺序排列书籍。

  1. 将模型的多对多 personToBook 更改为有序关系。这将使用NSOrderedSet 而不是NSSet。按字母顺序将书籍添加到有序集中。 (请注意,这种方法的一个缺点是 iCloud Core Data 同步不支持有序关系。)

  2. 将书籍的 NSSet 转换为数组并对该数组进行排序。

    person.personToBook?.allObjects.sort({ $0.bookName < $1.bookName })
    
  3. 使用 Book fetchedResultsController 来获取和订购一个人的书籍。添加指定人员实体的谓词,因此仅返回该人员的书籍。由于您是在比较一个实体,而不是一个名字,所以如果有多个作者使用该名字并不重要。

    let predicate = NSPredicate(format: "%K == %@", "bookToPerson", person)
    

顺便说一句,如果实体的属性或关系不是可选的,那么那些@NSManaged 属性就不需要是可选的。这将使您不必解开永远不会为零的值。您还可以指定集合中对象的类型,因此 Swift 知道它处理的是 Book,而不是 AnyObject。

    @NSManaged var personToBook: Set<Book> // Convention would be Book, not Books

您还可以避免传递上下文或 fetchedResultsController (of people)。您已经传递了一个具有 managedObjectContext 属性的 Person 托管对象,并且您正在直接访问该人的一对多 Book 关系以获取他们的书籍。 Book 视图控制器不需要知道主视图控制器碰巧获取的任何其他人。

【讨论】:

  • 我选择了选项 #3,效果很好。感谢您抽出宝贵时间发布此内容,并感谢其他建议。
  • 选项 #1 非常棒,只需单击一个按钮,它就起作用了!除了 icloud 同步之外,它还有什么缺点吗?这似乎太容易了
猜你喜欢
  • 2011-06-22
  • 1970-01-01
  • 1970-01-01
  • 2014-07-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多