在 Swift Core Data 中从一对多关系中获取对象

Posted

技术标签:

【中文标题】在 Swift Core Data 中从一对多关系中获取对象【英文标题】:Getting objects from to-many relationship in Swift Core Data 【发布时间】:2015-06-07 06:09:12 【问题描述】:

在使用 Swift 在 Core Data 中使用多对多关系时,我遇到了一些困难。

我的数据模型

我想要做的是使用Country 的一个实例,然后显示该国家/地区公民的所有Contacts。因为我一直在尝试这样做,所以我构建了一个 UITableViewController,它将显示该国的所有公民。但是,我在将实际的Contacts 脱离关系citizensOfCountry 时遇到了重大问题。这是我正在使用的代码(仅相关部分)。

class ShowingCitizensOfCountry: UITableViewController 

     var countryToShow: Country?
     //This is a value that is passed by a prepareForSegue method
     override func viewDidLoad() 
          //how do I get a list/set/other iterable object of Contacts?

          //***Line in question***
          let listOfPeople = countryToShow!.citizensOfCountry

          for citizen in listOfPeople 
              println(citizen)//THIS IS NOT WORKING
          

     

所以,这根本行不通。现在在 for 循环中,我得到一个编译器错误,上面写着Type 'Contacts' does not conform to protocol 'Sequence Type'。我对此不明白的是,它只是 Contact 类型……我认为这将是某种集合。所以,这不起作用,所以我尝试了这个。

let listOfPeople = countryToShow!.citizensOfCountry as! [Contacts]

这也不起作用,我收到错误'NSArray' is not a subtype of 'Contacts'。接下来我尝试使用 NSSet 进行转换。

let listOfPeople = countryToShow!.citizensOfCountry as! NSSet<Contacts>

不幸的是,这也不起作用,我收到警告 Cast from 'Contacts' to unrelated type 'NSSet' always failsCannot specialize non-generic type 'NSSet'。接下来我尝试了其他方法。我尝试使用valueForKey 方法。

let listOfPeople = countryToShow!.citizensOfCountry.valueForKey("name") as! Set<String>

这行得通!我可以只打印出该国所有公民的姓名。但是我不明白为什么。为什么当我使用 valueForKey("name") 时它可以工作,但我无法获得个人联系人?有没有更好的方法来做到这一点,我只是错过了?非常感谢任何关于为什么我无法从单个 Country 中获得 Contacts 集合的解释。谢谢。

【问题讨论】:

对不起,因为我真的很累,我无法阅读所有内容。但是从我读到的内容来看,你想得到一个应该是NSSet 的国家的公民。要做到这一点,您只需执行以下操作:yourArrayOfCountries.flatMap $0. citizensOfCountry.allObjects as! [Contacts] 。我会将其作为答案发布,以使其更易于阅读。 【参考方案1】:

对不起,因为我真的很累,我无法阅读所有内容。但是从我读过的内容来看,你想获得一个应该是 NSSet 的国家的公民。要做到这一点,你可以简单地做:

let contacts = yourArrayOfCountries.flatMap  
    $0.citizensOfCountry.allObjects as! [Contacts] 

根据您的评论:

let contacts = countryToShow!.citizensOfCountry.allObjects as! [Contacts]

【讨论】:

这可能是我在做一些愚蠢的事情,但我写了let listOfPeople = countryToShow!.citizensOfCountry.flatMap $0.citizensOfCountry.allObjects as! [Contacts] 并收到错误'Contacts' does not have a member named 'flatMap' 这是你的意思吗? 您只能在阵列上使用flatMap。您所做的是在NSSet 上,所以它不起作用。试试countryToShow!.flatMap $0.citizensOfCountry.allObjects as! [Contacts] 。我假设countryToShowCountry 的数组。 是的,这也不起作用。 countryToShow 是一个 Country 对象,我正在尝试按照关系查找该国的公民。如果您关心,我使用您的代码得到的错误是'Country' does not have a member named 'flatMap' 抱歉,我假设 countryToShow 是一个数组。我会更新答案。 let contacts = countryToShow!.citizensOfCountry.allObjects as! [Contacts] 应该可以工作。让我知道:)【参考方案2】:

您的错误的原因是一对多关系导致NSSet。您尝试通过这些集合进行迭代的所有尝试都应考虑到这一点。

更好的是实现NSFetchResultsController,这是在表格视图中显示核心数据的标准方式。

在 FRC 中,获取人员 根据需要对 FRC 进行排序 给它一个过滤countryToShow的谓词

FRC 实施:

var fetchedResultsController: NSFetchedResultsController 
    if _fetchedResultsController != nil 
        return _fetchedResultsController!
    

    let fetchRequest = NSFetchRequest(entityName: "Contact")
    fetchRequest.sortDescriptors = [NSSortDescriptor(key: "name", ascending: true)]
    fetchRequest.predicate = NSPredicate(format:"countryOfOrigin = %@", self.countryToShow!)
    let aFetchedResultsController = NSFetchedResultsController(
       fetchRequest: fetchRequest, managedObjectContext: self.managedObjectContext!, 
       sectionNameKeyPath: nil, cacheName: nil)
    _fetchedResultsController = aFetchedResultsController

    var error: NSError? = nil
    if !_fetchedResultsController!.performFetch(&error) 
        NSLog("%@", error!)
    

    return _fetchedResultsController!

var _fetchedResultsController: NSFetchedResultsController? = nil

我把 Contacts 改成了更合适的单数。

【讨论】:

那么在这个解决方案中我什至会使用citizensOfCountry 关系吗?还是我只是根据他们的countryOfOrigin 关系过滤所有联系人? 是一样的,因为它们是反向关系。因为您使用的是Contacts 实体,所以您将使用countryOfOrigin。我将修改我的答案,向您展示它是如何完成的。 只是为了我自己的好奇心,如果我已经找到了Country,那么使用citizensOfCountry 关系找到Contacts 会不会更有效,或者它会是一样吗? 原则上是的。但是,您无法将获取的结果控制器用于您的表格视图,并获得所有额外的好处。

以上是关于在 Swift Core Data 中从一对多关系中获取对象的主要内容,如果未能解决你的问题,请参考以下文章

Restkit, Swift, Core data 一对多

Core Data 上的一对多关系

如何在 Swift 中将 Core Data 与 Cloudkit 和许多设备同步

Core Data 获取请求与 NSFetchedResultsController 的一对多关系

Core Data 获取一对多关系的数据

如何管理 Core Data 中的一对多关系?