CoreData One-To-Many,对许多

时间:2015-11-29 05:28:21

标签: ios swift core-data

我有一个小应用程序,我正在努力学习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 the NSPredicate`,这样它只会为John Does中的一个提供书籍。

虽然我有一个,我可以在Person实体中添加某种UniqueID,就像我在SQL中做的那样。这将确保我只能为正确的人获取图书记录。我被告知我不应该在CoreData中这样做。这让我相信必须有一些方法来对这个项目中的多个部分进行排序。

我可以对书籍数据进行排序的方式有哪些?

1 个答案:

答案 0 :(得分:11)

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

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

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