Accessing Core Data entity name from NSArrayController -arrangedObjects - cocoa

Given an NSArrayController "objController" which is bound to the moc in IB, shouldn't the following work? And given that it doesn't seem to work, how do I go about retrieving an entity's name from my NSArrayController?
for (NSManagedObject *thisObj in [objController arrangedObjects])
{
NSEntityDescription *description = [thisObj entity];
NSString *entityName = [description name];
// do something with entityName...
NSString *entityAttributeValue = [thisObj valueForKey:#"attributeKey"];
// do something with entityAttributeValue...
}
The "objController" is IBOutlet-ed and set to "Entity Name" Mode, with the entity name set to an entity defined in the model. This entity does have child entities (and thus the reason I would like to access its description name, since the NSArrayController could store many different child entity types), but the presence of child entities doesn't seem to make a difference anyway.
... in the debugger, it looks like "description" is a valid NSEntityDescription object, but "entityName" gets set to a _PFEncodedString object, with no content. However, "entityAttributeValue" is just fine, populated with the correct value stored in Core Data.
One way around this, I suppose, would be to custom-class all my CD entities, then use -isKindOfClass to get the information I need.
Any ideas?

_PFEncodedString is a (private) concrete subclass of NSString and can therefore be used as any other NSString.

Related

NSArray ArrayController SelectedObjects nil

I have a coredata app with an Entity called Product.
In my interface I have an array controller for this entity called ProductAC. I have bound a table view and text fields to the array controller and can see the details, and I can add objects to it.
Now I want to create an export file for some of the objects. In the tableview I can select them, and then in the code I have this:
NSArray *uploadProducts = [ProductAC selectedObjects];
NSEnumerator *loop = [uploadProducts objectEnumerator];
This produces a nil value for the uploadProducts array.
How do I select the items to further process them? I have cleaned the file, closed and re-opened Xcode but I cannot seem to 'grab' the selected objects from the tableview?
thanks
Make sure you have the table view selectionIndexes property bound to the corresponding property on your array controller.

How can I bind to NSTableColumn's headerTitle?

I would like to bind NSTableColumn's headerTitle property to an NSMutableArray in my model layer (via an NSArrayController).
Basically I want to have an array where I can change values and have the table column header titles update. Is that reasonable?
However, the headerTitle binding wants an single NSString and I'm not sure how to connect my model object to this binding via my NSArrayController. Google does not give many hits for this problem.
My model layer consists of two class (both of which are appropriately KVC compliant). The first is a model which represents a single column title, it has one property title,
// A model class representing the column title of single NSTableColumn
#interface ColumnTitle : NSObject
#property NSString *title;
+ (ColumnTitle*) columnTitleWithTitle:(NSString*) aString;
#end
The second a model object which represents an ordered group of ColumnTitle objects,
// Class representing an order collection of model items
#interface TableColumnTitles : NSObject
#property NSMutableArray* columnTitles; // an array of ColumnTitle objects
// These are the KVC array accessors
-(void) insertObject:(ColumnTitle*)columnTitle inColumnTitlesAtIndex:(NSUInteger)index;
- (void)removeObjectFromColumnTitlesAtIndex:(NSUInteger)index;
- (void)replaceObjectInColumnTitlesAtIndex:(NSUInteger)index withObject:(ColumnTitle*)columnTitle;
#end
Note that TableColumnTitles object implements the above array accessors which are required for the bindings. Any suggestions?
Haven't tried that before but what you're actually asking for is using KVC for array indexes. A quick google didn't turn up anything on that issue except some results that indicate it's not (yet) possible (check this)
The easiest work-around I could come up with would be to simply add dedicated properties for the array indexes.. not nice but does the job.
So for a NSMutableArray called myArray and contains objects with title properties of type NSString you'd do something like:
#property (nonatomic, readonly, getter = columnOneGetter) NSString *columnOneString;
(NSString*) columnOneGetter
{
return myArray[0].title;
}
Always assuming of course their number is known in advance and we're not talking 200 columns :-)
I think this may/may not be what you're after, but quick google search landed me here:
http://pinkstone.co.uk/how-to-add-touch-events-to-a-uitableviewfooter-or-header/
edit: i realize this is for mac (not ios) but should be pretty easy to translate if it actually helps.

Understanding Core Data Queries(searching data for a unique attribute)

Since I am coming from those programmers who have used sqlite extensively, perhaps I am just having a hard time grasping how Core Data manages to-many relationships.
For my game I have a simple database schema on paper.
Entity: Level - this will be the table that has all information about each game level
Attributes: levelNumber(String), simply the level number
: levelTime(String), the amount of time you have to finish the level(this time will vary with the different levels)
: levelContent(String), a list of items for that level(and that level only) separated by commas
: levelMapping(String), how the content is layed out(specific for a unique level)
So basically in core data i want to set up the database so i can say in my fetchRequest:
Give me the levelTime, levelContent and levelMapping for Level 1.(or
whatever level i want)
How would i set up my relationships so that i can make this type of fetchRequest?
Also I already have all the data ready and know what it is in advance. Is there any way to populate the entity and its attributes within XCode?
As you've described it, it's a single Core Data entity, called Level that has four string attributes. Since there's just the one entity, there are no relationships. You'd create the one entity and add properties so that it looks just like you've described it above:
Getting just one Level is basic Core Data fetching:
NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:#"Level"];
NSString *levelNumber = #"1";
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"levelNumber = %#", levelNumber];
[request setPredicate:predicate];
NSError *error = nil;
NSArray *results = [[self managedObjectContext] executeFetchRequest:request error:&error];
NSManagedObject *level = nil;
if ([results count] > 0) {
level = [results objectAtIndex:0];
}
// Use level...
If it was me I'd use one of the numeric types for levelNumber, but maybe you have some reason to use a string there. I'd also probably break levelContent into a separate entity, because (a) comma delimited strings are ugly, no matter how you slice 'em, and (b) you might well want the items to have more attributes, and a separate entity would hold those.

How can NSArrayController sort on a to-many relationship?

Using CoreData, I have an entity "Bookmark", that has an to-many relationship named 'tags' to another entity "Tag", and some commun attributes (string, date, ...).
In a NSTableView we display the Bookmarks entity via Binding:
the NSArrayController is binded to File's Owner.managedObjectContext
(standard XCode CoreData template, the managedObjectContext is in the AppDelegate)
The columns in TableView are binded to their respective attribute. In particular the Tag column is binded to this arrayController.arrangedObjects.tags with a subclass of NSValueTransformer so that we can show, as an NSString, a summary of the to-many relationship.
It work. Now when I click on column header the whole table view get sorted correctly except for the 'tag' column where I get this:
-[_NSFaultingMutableSet compare:]: unrecognized selector sent to instance
For sure the "Set" from this to-many relationship doesn't respond to the selector 'compare:'.
Question:
How can I make this work ? How can I sort on a to-many relationship ?
Are something like the ValueTransformer available ? If I could supply a custom class that would do the compare: for the ArrayController to know...
One possible hack: since _NSFaultingMutableSet is a NSSet, we can add the selector 'compare:' via a categorie.
#interface NSSet (someAdditions)
- (NSComparisonResult)compare:(NSSet *)anotherSet;
#end
#implementation NSSet (someAdditions)
- (NSComparisonResult)compare:(NSSet *)aSet {
...
}
#end
we can now implement this compare: selector as we wish, like comparing the count of each set, or their NSString representation in some way.
It work in my App. I re-enabled the 'Creates Sort Descriptor' on the binding of the NSTableColumn and can now click on the header of my tableView to sort.
It's a hack because it affect all NSSet... But at least I have my hook.
What do you think ?

NSManagedObject setValue problem (Core Data)

I wish to edit an existing record in core data. At the moment, I have this code, but it creates a new record (and inserts the correct data into the correct column):
NSManagedObjectContext *context = [[NSApp delegate] managedObjectContext];
NSManagedObject *instrument = nil;
instrument = [NSEntityDescription insertNewObjectForEntityForName: #"Instrument"
inManagedObjectContext: context];
[instrument setValue:[NSNumber numberWithInt:quantityInStockInstruments]
forKey: #"quantity"];
The result will look like this:
Instrument | Value | Quantity
Violin | £25 | 9
| | 8 <<< This is the new record that is created, instead of setting the
quantity of violin from '9' to '8'
I want the program to edit the quantity column of the currently highlighted row, (which in this case is the 'violin' row. How would I do this?
As refulgentis said, the clue is in the name of the selector. You’re adding a new object.
A better way to do it, rather than using the table, is by using the selectedObjects of your NSArrayController. As an example (this is long winded for clarity and I’ve written it off the top of my head):
// Get the selected objects from the NSArrayController.
// There may be more than one object selected, so this needs to be accounted for.
NSArray *selectedObjectsArray = [yourArrayController selectedObjects];
// Get the first object in the array, this is the one that will have it's values changed.
id firstSelectedObject = [selectedObjectsArray objectAtIndex:0];
// Change a value in a KVC compliant way
[firstSelectedObject setValue:newValue forKey:#"keyValueToChange"];
Edited to add after the comment
Have you got an outlet to the array controller and connected it correctly in Interface Builder?
Anyway, the code works for me. Here’s an example project showing it working.
Note the selector name: "insert New Object:inContext".
As amrox says, it depends on how your model (i.e. Core Data) and your controller are connected. It's hard for me to say without knowing more about your code, especially since I'm usually more on the iPhone side of things (which doesn't have bindings), but basically you need to be saying [[yourDataArray objectAtIndex:[table selectedRow]] setValue:#"whatever" forKey:#"whatever"]

Resources