草庐IT

ios - CoreData 一对多,对多进行排序

coder 2023-09-08 原文

我正在开发一个小应用程序来学习 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 来提取图书列表,但是没有什么独特的东西可以将图书标识为属于特定用户。例如,我可以有两个同名的人 John Doe。正因为如此,我无法设置 NSPredicate` 以便它只会为 John Does 中的一本书拉入书籍。

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

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

最佳答案

NSSet 是无序的。该集合不会按照您添加它们的相同顺序返回书籍。

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

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

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

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

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

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

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

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

关于ios - CoreData 一对多,对多进行排序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33979716/

有关ios - CoreData 一对多,对多进行排序的更多相关文章

  1. ruby-on-rails - 使用 Ruby on Rails 进行自动化测试 - 最佳实践 - 2

    很好奇,就使用ruby​​onrails自动化单元测试而言,你们正在做什么?您是否创建了一个脚本来在cron中运行rake作业并将结果邮寄给您?git中的预提交Hook?只是手动调用?我完全理解测试,但想知道在错误发生之前捕获错误的最佳实践是什么。让我们理所当然地认为测试本身是完美无缺的,并且可以正常工作。下一步是什么以确保他们在正确的时间将可能有害的结果传达给您? 最佳答案 不确定您到底想听什么,但是有几个级别的自动代码库控制:在处理某项功能时,您可以使用类似autotest的内容获得关于哪些有效,哪些无效的即时反馈。要确保您的提

  2. ruby-on-rails - 按天对 Mongoid 对象进行分组 - 2

    在控制台中反复尝试之后,我想到了这种方法,可以按发生日期对类似activerecord的(Mongoid)对象进行分组。我不确定这是完成此任务的最佳方法,但它确实有效。有没有人有更好的建议,或者这是一个很好的方法?#eventsisanarrayofactiverecord-likeobjectsthatincludeatimeattributeevents.map{|event|#converteventsarrayintoanarrayofhasheswiththedayofthemonthandtheevent{:number=>event.time.day,:event=>ev

  3. ruby - 使用 C 扩展开发 ruby​​gem 时,如何使用 Rspec 在本地进行测试? - 2

    我正在编写一个包含C扩展的gem。通常当我写一个gem时,我会遵循TDD的过程,我会写一个失败的规范,然后处理代码直到它通过,等等......在“ext/mygem/mygem.c”中我的C扩展和在gemspec的“扩展”中配置的有效extconf.rb,如何运行我的规范并仍然加载我的C扩展?当我更改C代码时,我需要采取哪些步骤来重新编译代码?这可能是个愚蠢的问题,但是从我的gem的开发源代码树中输入“bundleinstall”不会构建任何native扩展。当我手动运行rubyext/mygem/extconf.rb时,我确实得到了一个Makefile(在整个项目的根目录中),然后当

  4. ruby - 如何进行排列以有效地定制输出 - 2

    这是一道面试题,我没有答对,但还是很好奇怎么解。你有N个人的大家庭,分别是1,2,3,...,N岁。你想给你的大家庭拍张照片。所有的家庭成员都排成一排。“我是家里的friend,建议家庭成员安排如下:”1岁的家庭成员坐在这一排的最左边。每两个坐在一起的家庭成员的年龄相差不得超过2岁。输入:整数N,1≤N≤55。输出:摄影师可以拍摄的照片数量。示例->输入:4,输出:4符合条件的数组:[1,2,3,4][1,2,4,3][1,3,2,4][1,3,4,2]另一个例子:输入:5输出:6符合条件的数组:[1,2,3,4,5][1,2,3,5,4][1,2,4,3,5][1,2,4,5,3][

  5. ruby - 即使失败也继续进行多主机测试 - 2

    我已经构建了一些serverspec代码来在多个主机上运行一组测试。问题是当任何测试失败时,测试会在当前主机停止。即使测试失败,我也希望它继续在所有主机上运行。Rakefile:namespace:specdotask:all=>hosts.map{|h|'spec:'+h.split('.')[0]}hosts.eachdo|host|begindesc"Runserverspecto#{host}"RSpec::Core::RakeTask.new(host)do|t|ENV['TARGET_HOST']=hostt.pattern="spec/cfengine3/*_spec.r

  6. ruby - 如何验证 IO.copy_stream 是否成功 - 2

    这里有一个很好的答案解释了如何在Ruby中下载文件而不将其加载到内存中:https://stackoverflow.com/a/29743394/4852737require'open-uri'download=open('http://example.com/image.png')IO.copy_stream(download,'~/image.png')我如何验证下载文件的IO.copy_stream调用是否真的成功——这意味着下载的文件与我打算下载的文件完全相同,而不是下载一半的损坏文件?documentation说IO.copy_stream返回它复制的字节数,但是当我还没有下

  7. ruby - 是否可以覆盖 gemfile 进行本地开发? - 2

    我们的git存储库中目前有一个Gemfile。但是,有一个gem我只在我的环境中本地使用(我的团队不使用它)。为了使用它,我必须将它添加到我们的Gemfile中,但每次我checkout到我们的master/dev主分支时,由于与跟踪的gemfile冲突,我必须删除它。我想要的是类似Gemfile.local的东西,它将继承从Gemfile导入的gems,但也允许在那里导入新的gems以供使用只有我的机器。此文件将在.gitignore中被忽略。这可能吗? 最佳答案 设置BUNDLE_GEMFILE环境变量:BUNDLE_GEMFI

  8. ruby - 在 Windows 机器上使用 Ruby 进行开发是否会适得其反? - 2

    这似乎非常适得其反,因为太多的gem会在window上破裂。我一直在处理很多mysql和ruby​​-mysqlgem问题(gem本身发生段错误,一个名为UnixSocket的类显然在Windows机器上不能正常工作,等等)。我只是在浪费时间吗?我应该转向不同的脚本语言吗? 最佳答案 我在Windows上使用Ruby的经验很少,但是当我开始使用Ruby时,我是在Windows上,我的总体印象是它不是Windows原生系统。因此,在主要使用Windows多年之后,开始使用Ruby促使我切换回原来的系统Unix,这次是Linux。Rub

  9. Ruby 文件 IO 定界符? - 2

    我正在尝试解析一个文本文件,该文件每行包含可变数量的单词和数字,如下所示:foo4.500bar3.001.33foobar如何读取由空格而不是换行符分隔的文件?有什么方法可以设置File("file.txt").foreach方法以使用空格而不是换行符作为分隔符? 最佳答案 接受的答案将slurp文件,这可能是大文本文件的问题。更好的解决方案是IO.foreach.它是惯用的,将按字符流式传输文件:File.foreach(filename,""){|string|putsstring}包含“thisisanexample”结果的

  10. Get https://registry-1.docker.io/v2/: net/http: request canceled while waiting - 2

    1.错误信息:Errorresponsefromdaemon:Gethttps://registry-1.docker.io/v2/:net/http:requestcanceledwhilewaitingforconnection(Client.Timeoutexceededwhileawaitingheaders)或者:Errorresponsefromdaemon:Gethttps://registry-1.docker.io/v2/:net/http:TLShandshaketimeout2.报错原因:docker使用的镜像网址默认为国外,下载容易超时,需要修改成国内镜像地址(首先阿里

随机推荐