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"]
Related
I am using a UIPickerView and currently their is only a single object in it. How can I display that single object on label.
It has this weird property that when we use pickerView the data is not set selected by default.Once we choose another object or roll it, then only any particular object is selected. Hence if only one object is their in pickerView. It does not count as selected even though when you tap on that single object.
I tried a lot but found that if their are more than one object then only you can display the selected object on label but not if their is only one object.
You need to make a code that is triggered when the UIPickerView changes, like this:
#pragma
-(void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component
//Action that triggers following code:
{
NSString *nameString = [nameOnMutubaleArrayYouWannaGetDataFrom objectAtIndex:[picker selectedRowInComponent:0]]; //Or 1 if u have multiple rows
NSString *labelString = [[NSString alloc]initWithFormat:
#" %# ", nameString];
labelOutput.text = labelString;
Hope this helps.
Thanks for reading:
I've gotten stuck on this problem before and I know there is a solution, but after a a few hours of searching I haven't been able to find it again.
I'm using an NSForm and an "Add" button to create a new instance of a student and add that student to an array (sessionRoster). No problems here.
- (IBAction)addNewStudentButtonPressed:(id)sender {
//CREATE NEW STUDENT
Student *newStudent = [[Student alloc] init];
//ASSIGN VALUES FROM FORM
newStudent.firstName = [[studentForm cellAtIndex:0] stringValue];
newStudent.lastName = [[studentForm cellAtIndex:1] stringValue];
//ADD STUDENT TO ROSTER
[sessionRoster addObject:newStudent];
//CLEAR FORM
[[studentForm cellAtIndex:0] setStringValue:#""];
[[studentForm cellAtIndex:1] setStringValue:#""];
}
I'm using an Array controller to display the array in a tableview. No problems here. I have the bindings correct, because I've included some "dummy" students in the init, and they appear when the program is run (I wanted to post the screenshot, but I don't have enough reputation).
My question is, how can I make the table update each time the "add" button is pressed?
I do have the table as a property, and calling [tableView reloadData] doesn't work. I believe the solution before was some kind of "contentWillUpdate:YES" and "contentDidUpdate:YES" pairing, but I can't find that information again.
Thanks for your time!
J
Add the student object to the arrayController not to the array. The array controller "does the lifting."
I have two coloumn in NSTableView as Name and Salary with 5-10 values. I want to sort these coloumn after click on header of both the column. There is lots of data present in Internet but I am not able to use these. Please help me to do this in cocoa.
Thanks in advance and appreciate any help.
Each table column has a method setSortDescriptorPrototype
Sort descriptors are ways of telling the array how to sort itself (ascending, descending, ignoring case etc.)
Iterate over each of the columns you want as sortable and call this method on each of those columns, and pass the required sort descriptor (In my case I'll be using the column identifier)
for (NSTableColumn *tableColumn in tableView.tableColumns ) {
NSSortDescriptor *sortDescriptor = [NSSortDescriptor sortDescriptorWithKey:tableColumn.identifier ascending:YES selector:#selector(compare:)];
[tableColumn setSortDescriptorPrototype:sortDescriptor];
}
After writing this piece of initialization code, NSTableViewDataSource has a method - (void)tableView:(NSTableView *)aTableView sortDescriptorsDidChange:(NSArray *)oldDescriptors that notifies you whenever a sort descriptor is changed, implement this method in the data source and send a message to the data array to sort itself
- (void)tableView:(NSTableView *)aTableView sortDescriptorsDidChange:(NSArray *)oldDescriptors
{
self.data = [self.data sortedArrayUsingDescriptors:sortDescriptors];
[aTableView reloadData];
}
This method will get fired each time a column header is clicked, and NSTableColumn shows a nice little triangle showing the sorting order.
I stumbled upon this question while looking for the easiest way of implementing something similar. Although the original question is old, I hope someone finds my answer useful! Please note that I am using Xcode 5.1.1
Ok so to do this you need to:
select the actual column you want to sort in your table.
In your Attributes Inspector you need to fill in two fields: Sort Key, and Selector.
In the Sort Key field, you need to enter the value of your Identifier. The value of your Identifier is located in your Identity Inspector.
In the Selector field you need to enter a suitable selector method based on the object type in the column. The default method is; compare:
Based on the Table View Programming Guide for Mac. The compare: method works with NSString, NSDate, and NSNumber objects. If your table column contains only strings, you may want to consider using the caseInsensitiveCompare: method if case sensitivity is unimportant. However, consider replacing these method signatures with the localizedCompare: or localizedCaseInsensitiveCompare: methods to take into the account the user’s language requirements.
Finally, you need to declare the tableView:sortDescriptorsDidChange: method in your Table View Controller in the format shown below:
-(void)tableView:(NSTableView *)mtableView sortDescriptorsDidChange:(NSArray *)oldDescriptors
{
[listArray sortUsingDescriptors: [mtableView sortDescriptors]];
[tableView reloadData];
}
Just had lately the same issue to get tableView sorted.
My approach :
bind your sortDescriptors to tableview's arrayController
bind tableview's sortDescriptors to Arraycontroller's sort descriptor
perform the settings in attribute inspector (see Tosin's answer above)
Worked perfect for me. No need to set prototypes for columns or something else.
Thanks very much ,It is usefullly for my question.
my code like this
First, set unique values in the XIB interface,like name...
- (void)viewDidLoad {
[super viewDidLoad];
self.itemTableView.dataSource = self;
self.itemTableView.delegate = self;
self.itemTableView.selectionHighlightStyle = NSTableViewSelectionHighlightStyleRegular;
self.itemTableView.usesAlternatingRowBackgroundColors = YES;
for (NSTableColumn *tableColumn in self.itemTableView.tableColumns ) {
NSSortDescriptor *sortDescriptor = [NSSortDescriptor sortDescriptorWithKey:tableColumn.identifier ascending:NO selector:#selector(compare:)];
[tableColumn setSortDescriptorPrototype:sortDescriptor];
}
}
-(void)tableView:(NSTableView *)tableView sortDescriptorsDidChange:(NSArray<NSSortDescriptor *> *)oldDescriptors{
NSLog(#"sortDescriptorsDidChange:%#",oldDescriptors);
[self.itemArr sortUsingDescriptors:[tableView sortDescriptors]];
[self.itemTableView reloadData];
}
I have an NSTableview which s bound to a NSArrayController. The Table/Arraycontroller contains Core Data "Person" entities. The people are added to the NSTableview by the GUI's user.
Let's say a person entity looks like
NSString* Name;
int Age;
NSString* HairColor;
Now I want to iterate over what is stored in the array controller to perform some operation in it. The actual operation I want to do isn't important I don't really want to get bogged down in what I am trying to do with the information. It's just iterating over everything held in the NSArraycontroller which is confusing me. I come from a C++ and C# background and am new to Cocoa. Let's say I want to build a NSMutableArray that contains each person from nsarraycontroller 1 year in the future.
So I would want to do something like
NSMutableArray* mutArray = [[NSMutableArray alloc] init];
foreach(PersonEntity p in myNsArrayController) // foreach doesn't exist in obj-c
{
Person* new_person = [[Person alloc] init];
[new_person setName:p.name];
[new_person setHairColor:p.HairColor];
[new_person setAge:(p.age + 1)];
[mutArray addObject:new_person];
}
I believe the only thing holding me back from doing something like the code above is that foreach does not exist in Obj-c. I just don't see how to iterate over the nsarraycontroller.
Note: This is for OSX so I have garbage collection turned on
You're looking for fast enumeration.
For your example, something like
for (PersonEntity *p in myNsArrayController.arrangedObjects)
{
// Rest of your code
}
You can also enumerate using blocks. For example:
[myNsArrayController enumerateObjectsUsingBlock:^(id object, NSUInteger index, BOOL *stop)
{
PersonEntity *p = object;
// Rest of your code
}];
There's pro's and cons to both approaches. These are discussed in depth in the answer to this question:
Objective-C enumerateUsingBlock vs fast enumeration?
You can find a great tutorial on blocks in Apple's WWDC 2010 videos. In that they say that at Apple they use blocks "all the time".
I have an NSTableView with columns bound to an NSArrayController.
The table view shows a list of email messages:
Flag if unread
Subject
Attachment size
The user can click on the Attachment Size column to sort the list, but I would like the table to always be sorted by the "unread" flag first so that the unread messages always remain at the top of the list.
I did not bind the Array Controller's sort descriptors to anything, yet table sorting works magically by clicking on the table columns (why?). Is there some way I can intercept setting the Array Controller's sort descriptors and insert the "Unread" sort descriptor first?
Example of a table sorted by attachment size:
UNREAD▼ SUBJECT ATTACHMENT SIZE▼
------ ------- ------------------
yes Hello.. 110kb
yes Test... 90kb
no Foobar 200kb
no Hey 100kb
no Test2 10kb
Well, the reason it "just works" is because the table columns call setSortDescriptors: on their bound NSArrayController.
Assuming you want the table to remain sortable, but you always want to sort by "unread", this is how I would go about it:
First, subclass NSArrayController and override arrangeObjects:
- (NSArray *)arrangeObjects:(NSArray *)objects {
NSMutableArray *oldSorted = [[super arrangeObjects:objects] mutableCopy];
NSMutableArray *newSorted = [NSMutableArray arrayWithCapacity:[oldSorted count]];
for (id anObject in oldSorted)
if ([[anObject valueForKey:#"isUnread"] boolValue])
[newSorted addObject:anObject];
[oldSorted removeObjectsInArray:newSorted];
[newSorted addObjectsFromArray:oldSorted];
[oldSorted release];
return newSorted;
}
This puts unread messages at the "top" (beginning of array). I'm not sure this is the most efficient sorting algorithm, but I believe it's the correct way to go about it.
I think that you can just set an array of sortDescriptors on your array controller during awakeFromNib. No need to force arrangeObjects:, this functionality totally built in.
- (void)awakeFromNib {
[super awakeFromNib];
NSSortDescriptor *unreadSorter = [[NSSortDescriptor sortDescriptorWithKey:#"isUnread" ascending:NO)] autorelease];
NSArray *arrayOfSortDescriptors = [NSArray arrayWithObject:unreadSorter];
[self setSortDescriptors:arrayOfSortDescriptors];
}
The columns will still remain sortable when you click the column header.