I have been having some difficulties revolving around using to-many relationships in Core Data with Swift.
My data model
What I am trying to do is to use an instance of a Country
and then display all of the Contacts
that are citizens of that country. As I have been trying to do this, I have constructed a UITableViewController that will display all of the citizens of the country. However I have had major problems of getting the actual Contacts
out of the relationship citizensOfCountry
. Here is the code that I am using (only relevant parts).
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
}
}
So, this is not working at all. Right now in the for loop I get a compiler error that says Type 'Contacts' does not conform to protocol 'Sequence Type'
. What I don't understand about this is that it is just of type Contact... I would think that it would be some sort of collection. So, that wasn't working so I tried this.
let listOfPeople = countryToShow!.citizensOfCountry as! [Contacts]
This doesn't work either and I get the error 'NSArray' is not a subtype of 'Contacts'
. Next I tried converting with a NSSet.
let listOfPeople = countryToShow!.citizensOfCountry as! NSSet<Contacts>
Unfortunately this doesn't work either and I get the warnings Cast from 'Contacts' to unrelated type 'NSSet' always fails
and Cannot specialize non-generic type 'NSSet'
. Next I tried something else. I tried using the valueForKey
method.
let listOfPeople = countryToShow!.citizensOfCountry.valueForKey("name") as! Set<String>
This works! I could print out just the name of all the people that are a citizen of that country. However I don't understand why. Why does it work when I use valueForKey("name")
but I can't get an individual Contact? Is there a better way to be doing this that I have simply missed? Any explanation about why I am not able to get a collection of Contacts
from a single Country
is greatly appreciated. Thanks.
In some respects, an NSManagedObject acts like a dictionary—it's a generic container object that provides efficient storage for the properties defined by its associated NSEntityDescription instance.
Inverse relationships enable Core Data to propagate change in both directions when an instance of either the source or destination type changes. Every relationship must have an inverse. When creating relationships in the Graph editor, you add inverse relationships between entities in a single step.
Fetched Properties in Core Data are properties that return an array value from a predicate. A fetched property predicate is a Core Data query that evaluates to an array of results.
Core Data allows us to store integers, booleans, strings, UUID, date, etc. but sometimes we want to store a specific data type like UIColor, UIImage, our own class, struct, or enum, and even arrays, but that is simply not an option in Attribute's Type.
Sorry because I'm really tired I couldn't read everything. But from what I've read, you want to get the citizens of a country which should be a NSSet. To get that you can simply do:
let contacts = yourArrayOfCountries.flatMap {
$0.citizensOfCountry.allObjects as! [Contacts]
}
According to your comment:
let contacts = countryToShow!.citizensOfCountry.allObjects as! [Contacts]
The reason for your errors is that the to-many relationship results in a NSSet
. All of your attempts to iterate though these sets should take this into account.
Much better is to implement a NSFetchResultsController
, the standard way for displaying Core Data in a table view.
countryToShow
FRC implementation:
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
I made Contacts into the more appropriate singular.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With