Get index path of CoreData one-to-many relationship? - ios

I'd expect to have something like [_contact.phones objectAtIndexPath:indexPath]; available to me. Where _contact is my core data object and phones is a to many relationship from the contact. Yet this is not available to me. I'm trying to do this in my cellForRowAtIndexPath implementation (where phones would be its own section) yet I can't figure out how to do this without adding phones to an external array at the time of loading then using that instead.
Could someone give me some advice as to how to go about this?

Core data to-many relationships use NSSet. If you check "ordered" in XCode it will become an NSOrderedSet which has an objectAtIndex method.
You would not want to use the unordered set because even if you got an array of objects with NSSet's allObjects method, the ordering is not necessarily the same every time you call it.
See for instance this answer:
Ordered Sets and Core Data (NSOrderedSet)
objectAtIndexPath would make sense if the data structure were a tree and not an array.

Related

Save multiple values per key in CoreData

I'm currently looking into CoreData and need to save multiple values per key. In my case I just need to save a couple of strings, max 9, for a single Key in CoreData.
Specifically, I want to save players for a game. My game object already contains relationship objects to these players, but I also want to save the Player names as records on the game object itself, as players can be deleted by my users and I want my game objects to be immune for that.
I know in Cloudkit you can set the value of a certain key to e.g. "set of strings", and this can be done in CoreData relationships to when creating a one-to-many relationship. I was wondering if there is a by-the-book way to do this in regular CoreData key-value pairs as well.
It's easier to think about CoreData as objects rather than low-level data storage. It's not really designed as a key/value system (except in the sense that any object's properties can be thought of as a dictionary).
For the example you give, it might be more in keeping with CoreData's object persistence style to flag deleted players as unavailable rather than removing them, so that your history remains intact.
You could use an attribute of type Transformable to store your set. NSArray and NSSet conform to NSCoding so CoreData can take care of all data transforming, archiving and unarchiving for you.

Strategy for user-managed predicates to filter Core Data entity list

I've been thinking about this and searching for an answer for over two weeks to no avail.
I've created a form to allow a user to make selections to build a simple NSPredicate to filter a main list of entities. I want the user to be able to view the predicates they've created and to also be able to delete them if they choose. Currently, the form will allow me to get both the plain text representation of the predicate such as, "My dog is black" and the predicate string such as "furColor == black".
I'm looking for a way to store these so that I can use them quickly in the NSFetchResultsController for the main entity and so I can also display them in their own table view so that they can be deleted on the fly. Does anyone know a good approach for this?
I've been thinking of keeping them in an entity table (with the plain text string and the predicate as a string or as binary data as an NSPredicate) or as a NSDictionary inside the NSUserDefaults. I'm not sure which would be better performance-wise, either to get the NSDictionary from the defaults, construct and initialize the predicates, or to fetch them from the database and then fetch the main entities.
I also hesitate to use the NSDictionary route because the order won't be guaranteed when the user views the list of predicates they've defined.
Any help is appreciated. Thanks!
The NSUserDefaults options seems the most practical to me. Perhaps this feature has little to do with your actual data model, so it seems wrong to mix the two. It should be very easy to use this scheme in another app.
As for sorting, you could simply add a creationDate key that you can use to sort. Or you can sort by any other key.
There should be no performance difference as long as the list of predicates is not too long (several 100 entries). NSUserDefaults uses an SQLite persistent store in the background which is presumably the same you are using for Core Data.
This sentence is not quite clear
I'm not sure which would be better performance-wise, either to get the NSDictionary from the defaults, construct and initialize the predicates, or to fetch them from the database and then fetch the main entities.
You construct the predicate from the user defaults and fetch from Core Data. Don't store Core Data entities in user defaults.

How to store other NSManagedObjects as property of a NSManagedObject

I am new to iOS programming and I'm doing up a simple function of an iOS application. Currently, I've created an entity called Players, and I'd like the entity to have a property, in which it stores other NSManagedObject like an array.
This is because I want a player to be able to have friends in the game and this is the way I've thought of; I could just access a player's friend's list via
[playername friendList]
May I know if this is the way to do so? Because for an entity's attribute type, I couldn't use NSMutableArray or NSArray as its type. If it is, may I know how I can store it? If not, is there a better way to achieve that?
This is the purpose of relationships in the Core Data model. Add a relationship between the two entities (and an inverse) and add the managed objects to that relationship.
See this section of the Core Data guide.
You need to create a relationship between the models, which are represented with NSSet (or NSOrderedSet, by checking "ordered", if the order is important.)
Ordered Sets are similar to arrays, except all the objects are distinct (no duplicates).

Are the accessor methods created by to-many relationships as good as NSFetchedResultsControllers?

My question is similar this one here:
ResultsController to another ResultsController
A typical app structure on ios is to drill down into data via table views, and plenty of app models are hierarchical. For example, a Film Festival could have many Films, which could have many Screenings, which could have many Attendees. If we use Core Data to represent this model, then we can use an NSFetchedResultsController to populate Films into a UITableView. Using the NSFetchedResultsController helps greatly with performance and memory efficiency, and provides built-in support for observing changes to the underlying data. I would like to take advantage of this in my project as much as I can.
So if we have a table of Films backed by this sweet NSFetchedResultsController, and the user selects a Film to see a list of its Screenings, we can pass that Film (a subclass of NSManagedObject) to a new UITableViewController and populate that table with the film's screenings.
The core of my question is not "How do I do this?" Instead, it's asking if the benefits of NSFetchedResultsController travel along with the NSManagedObject. I could build a new results controller using the event in the predicate, but I don't need to. If I pass the Film object into a variable called film, and my to-many relationship is identified as screenings, then I believe I can get the set of screenings related to that film like this:
NSSet *filmScreenings = [film screenings];
If I turn that set into an array, and use that as the data backing my new table view of screenings, am I losing the benefits of the NSFetchedResultsController? My gut tells me yes, especially the support for monitoring changes - but an FAQ in Apple's docs made me second guess and ask the community at large. Check out the question in this FAQ called "I have a to-many relationship from Entity A to Entity B..."
Should I use that accessor method then, or should I build a new NSFetchedResultsController?
You will lose the benefits of NSFetchedResultsController by doing this (e.g. batch fetching and change monitoring), as you're going to replace it with a simple NSArray. You're best bet is to pass your Film to the details controller, and construct an NSFetchedResultsController using this Film in the predicate for the NSFetchRequest.

Create NSFetchedResultsController managing entities with many to many relationship

I have an entity called Project and another entity called Employee. Employees work on multiple projects.
Project entity has project name.
Employee entity has First name, last name, departmentid number.
I want the data to show up in section header table like this
Project 1
Dept1
-firstname1, lastname1
-firstname2,lastname2
dept 2
firstname3, lastname3
firstname4,lastname4
Project 2
Dept1
-firstname1,lastname1
How can I do this? I don't have to display department names, but it has to be sorted that way.
I am using Core Data & UITableView. I need to construct NSFetchResultsController for this.
I think the root of your question comes from the fact that a to-many relationship results in an NSSet when you access it from the from object of the relationship (ie: Project->Employees - results in an NSSet of employees). NSSets are, of course, unordered.
And the answer is this:
You'll need to sort your employee NSSets by hand. I suggest you convert the NSSet to an NSMutableArray, and then use -sortUsingBlock: or something along those lines to do it. To keep yourself from having to re-sort it every time you need it, store it as a member variable of your Project class. In doing so, it should be pretty easy to create it lazily, and only re-sort it when the dataset changes, which will be better for performance.
You MIGHT be able to do something with a subquery in Core Data... but I think you might find that'll hit the disk more often than you might like. (Just a guess there) The technique I've suggested above is a bit less magical, a bit more brute force, but it'll work, and you'll know exactly how it behaves forever.
Use fetchedResultsController to get your 'Project' entities and you will be able to access and display the Employee NSSet in your tableview datasource methods via their relationships.

Resources