NSMutableArray add data to NSTableView creating an empty row? - objective-c

I've create a function below which will call when a button is pressed:
- (IBAction)setData:(id)sender{
[_myArrayController addObject:[NSMutableDictionary dictionaryWithObjectsAndKeys:
#"James", #"Name",
#"Smith",#"Surname", nil]];
}
On My NSTableView I have two columns both NSTableViewColumns have been binded to the keys above Name for the first and Surname for the second for the arrangedObjects controller key.
When I press the button a new row is created however both column fields are blank rather than saying James Smith.
Any ideas what I could be doing wrong?

Related

Restoring selection to NSPopUpButton on loading a form

Please help, this is driving me mad :(
I have a form as part of an OSX Cocoa app i'm writing which uses an NSPopUpButton to select the type of record you are creating/editing.
I am using bindings to bind the popup button to an array controller and my selected value is bound to an NSString.
I can get the popup populated and can select an item and save the record ok but there are two things I can't get right:
1) The selected value object contains the textual name of the item rather than its key - I have set Content Objects binding
2) I cannot restore the popup's selected item on reloading the form.
Here's some code samples to assist:
#implementation snippet:
IBOutlet NSPopUpButton *popMediaType;
IBOutlet NSArrayController *acMediaTypes;
#property (nonatomic, copy) NSString *selMediaType;
#interface snippet:
- (void)setupForm {
NSArray *types = [[NSArray alloc] initWithObjects:[NSDictionary dictionaryWithObjectsAndKeys:#"Video", #"name", #"video", #"value", nil],
[NSDictionary dictionaryWithObjectsAndKeys:#"Advert", #"name", #"advert", #"value", nil],
[NSDictionary dictionaryWithObjectsAndKeys:#"Graphic", #"name", #"graphic", #"value", nil],
nil];
[acMediaTypes setContent:types];
}
In interface builder:
acMediaTypes is the referencing outlet for an array controller object called mediaTypes
popMediaType is the referencing outlet for the NSPopUpButton on the form
My NSPopUpButton's bindings is configured thus:
Content (mediaTypes.arrangedObjects)
Bind to: mediaTypes
Controller Key: arrangedObjects
Model Key Path: <null>
Content Objects (mediaTypes.arrangedObjects)
Bind to: mediaTypes
Controller Key: arrangedObjects
Model Key Path: value
Content Values (mediaTypes.arrangedObjects)
Bind to: mediaTypes
Controller Key: arrangedObjects
Model Key Path: name
Selected Value (File's Owner.selMediaType)
Bind to: Files Owner
Controller key: <null>
Model Key Path: selMediaType
The popup displays correctly, shows the text from the "name" portion of the array properly.
If I read selMediaType in my code using something like NSLog() then I see "Video" for example if that item is selected - it should be "video" (lower case from the "value" part of the dictionary)
I can store the values in my sqlite database with no problems and inspect them using sqlite3 from the terminal and everything is saved.
If I load the values back from the table, I would have thought that just setting selMediatype would have reset the item position in the NSPopUpButton but it doesn't.
Solution was easy in the end but not obvious to the new players to the game.
First, your recipient variable to bind the selection to must be a property not just an iVar
Second, in the bindings, bind selected object, NOT selected value.
Binding selected value will put the displayed valued in your target variable eg "Video" but binding to selected object will put the key in your target variable eg "video".

Set checkbox inside NSTableView to "YES"

I have an NSTableView with a checkbox column and an NSArrayController.
The NSTableView is bound to the NSArrayController to show its content.
The checkbox column is bound to imgArrayController.arrangedObjects.check1. When the program starts the array is empty. I add values using the arrayController in a loop this way:
[imgArrayController addObject:[NSDictionary dictionaryWithObjectsAndKeys:
[NSImage imageNamed: [NSString stringWithFormat:#"%#" ,fileName]], #"image",
[NSString stringWithFormat:#"%#" ,fileName], #"filename",
#"YES", #"check1",
nil]];
The correct number of rows are added, however I am getting an error when it tries to set checkbox to YES. This is the error I get:
2013-02-03 19:11:46.357 Stockuploader[561:303] Error setting value for key path check1 of object {
} (from bound object <NSTableColumn: 0x100152280> identifier: check1): [<__NSDictionaryI 0x10010c190> setValue:forUndefinedKey:]: this class is not key value coding-compliant for the key check1.
Could somebody please help me to understand what I am doing wrong? The rows appear inside the table but they are all empty.
Try using NSMutableDictionary instead of NSDictionary. Also try using [NSNumber numberWithBool: YES] instead of #"YES" (which is a string, not a boolean).
EDIT:
In a cell-based NSTableView you would need to bind the column (not the cell itself) to the arrayController with a Controller Key of arrangedObjects and a Model Key Path of check1.
In a view-based NSTableView you would need to bind the checkbox control to the Table Cell View with a Model Key Path of objectValue.check1.

NSArrayController populates NSTableView but doesn't set the cell title

I have a two column NSTableView that I want to populate with entries grabbed from a CSV file. Everything works fine except the title of each of the table cells isn't set.
Here's the function that is called for each row in the NSArray
- (void)populateTable:(NSString *)fname :(NSString *)lname {
NSMutableDictionary *value = [[NSMutableDictionary alloc] init];
[value setObject:[NSString stringWithFormat:#"%#", fname] forKey:#"first_name"];
[value setObject:[NSString stringWithFormat:#"%#", lname] forKey:#"last_name"];
[arrayController addObject:value];
[value release];
[fname_list reloadData];
[lname_list reloadData];
}
The value of the "last name" column is bound to the Array Controller arrangedObjects.last_name and both "first_name" and "last_name" are listed as keys in the Array Controller > Object Controller > Keys list
The proper amount of table cells are created (3 entries in the CSV file = 3 rows in each column), but the title of each of the cells isn't set (either to "first_name" or "last_name" depending on the column); the title of the cells just remains "Table View Cell"
Edit:
After using navinsillu's changes I end up with the following function:
- (void)populateTable:(id)sender :(NSString *)fname :(NSString *)lname {
[arrayController insert:sender];
[[[self arrayController] selection] setValue:fname forKeyPath:#"first_name"];
[[[self arrayController] selection] setValue:lname forKeyPath:#"last_name"];
[fname_list reloadData];
[lname_list reloadData];
}
And in my header I have
#property (retain,nonatomic,readwrite) IBOutlet NSArrayController *arrayController;
But I still get the same results: 3 rows/cells in each table column, all titled "Table View Cell"
Edit:
After some inspection I noticed that the Model Key Path under the Value bind for the table columns doesn't have any entries. When I type in first_name or last_name it says No completions found even though the keys are listed in the Keys list in the array controller. Unfortunately I have no idea as to why it isn't finding the keys.
Edit:
Odd. I tried deleting and adding the table view and array controllers but that didn't work. However, creating a new project and doing the exact same things produces the expected results.
You can set your title at the table header in Interface Builder.you can double click the table column header and set title for it.
Recreating the project exactly the same way as I had it produces what I was expecting to happen. I'm not sure why redoing it all worked, but it did.

Populate and bind an NSTableView to multiple array controllers

I have an API provided NSArray with a bunch of content objects – we'll call this acquiredFruit – and an empty NSMutableArray called likedFruit.
I've created NSArrayControllers for both arrays and bound my TableView to acquiredFruit.arrangedObjects. The first column of the tableView is bound to arrangedObjects.name and correctly shows all the delicious fruit.
I've created a second column with a checkbox – when the user fills the box I'd like to add the fruit to my likedFruit array. Unchecking the box should remove the fruit object from the likedFruit array.
Essentially I'd like my NSTableView to join between two array controllers. I have a feeling I should be making a single separate controller for this, but I'm unsure how to approach the problem.
I should also mention that I'm aware I could iterate through my array and construct another object with the fields I need, but my goal is to do this by using bindings, if possible.
Thoughts?
I think you should use one array controller.
You can have an attribute on Fruit called liked. Now your "liked" checkbox column is connected to arrangedObjects.liked. Later, when you want to determine the set of all liked fruits, you can query your fruits array:
NSArray * likedFruits = [ allFruitsArray filteredArrayUsingPredicate:[ NSPredicate predicateWithFormat:#"liked = YES"] ] ;
If in another part of your UI you are displaying only liked fruit, you can set your array controller's filterPredicate to the predicate above to get just those fruits.
EDIT: Let's say NSFruit is provided via someone else's API. Let's use the "General Technique for Adding Properties to Someone Else's Class":
#interface NSFruit (Liking)
#property ( nonatomic ) BOOL liked ;
#end
#implementation NSFruit (Liking)
-(BOOL)liked
{
return [ objc_getAssociatedObject( self, "_abliked" ) boolValue ] ;
}
-(void)setLiked:(BOOL)b
{
objc_setAssociatedObject( self, "_abliked", [ NSNumber numberWithBool:b ], OBJC_ASSOCIATION_RETAIN_NONATOMIC ) ;
}
#end
(I've written this same code for like 100 posts recently!)
I'm not at my Xcode computer right now, so i can't test this, but it seems like you don't really need another array controller, but just another array to hold the likedFruits. I think you need to create an array of dictionaries from your acquiredFruits array that would have one key for the fruit name and another key with a bool value for whether the check box is checked --this bool would be bound to your second column. I'm not sure about the next step on how to tell the likedFruit array that it need to add a new fruit -- I think the check box could have an action method that you could use to have the likedFruit array add the object in the row where the check box was clicked.
After Edit:
Here is an example of how to do what I suggested. I take an array of fruits and turn it into an array of dictionaries (called theData) that include a key for the value of your check box (In IB the content array of the array controller is bound to theData, and the columns are bound to Array Controller.arrangedObjects.fruitName and Array Controller.arrangedObjects.isLiked). checkChanged is an IBAction connected to the check box (but note the sender is actually the table view), and I use the value of the check box to determine whether to add a fruit to likedFruits or delete one. I put one more method, connected to a button just to check the values in likedFruits.
#implementation AppDelegate
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
self.theData = [NSMutableArray array];
self.likedFruit =[NSMutableArray array];
NSArray *acquiredFruits = #[#"Apple",#"Orange",#"Pear",#"Peach"];
for (NSString *aFruit in acquiredFruits) {
NSDictionary *dict = [NSDictionary dictionaryWithObjectsAndKeys:aFruit,#"fruitName",[NSNumber numberWithBool:NO],#"isLiked", nil];
[self.theData addObject:[dict mutableCopy]];
}
self.theData = _theData;
// NSLog(#"%#",self.theData);
}
-(IBAction)checkChanged:(NSTableView *)sender { //connected to the button cell in the table view (but sender is the table view)
NSString *theFruit = [[self.controller.arrangedObjects objectAtIndex:sender.clickedRow ] valueForKey:#"fruitName"];
BOOL doWeLikeIt = [[[self.controller.arrangedObjects objectAtIndex:sender.clickedRow] valueForKey:#"isLiked"] boolValue];
if (doWeLikeIt) {
[self.likedFruit addObject:theFruit];
}else{
[self.likedFruit removeObject:theFruit];
}
}
-(IBAction)logLikedFruits:(id)sender {
NSLog(#"%#",self.likedFruit);
}

How to Add Checkbox Cell to NSTableView with Cocoa Bindings?

I'm new in Cocoa. I have a table that stores Contacts. I'm not using NSTableView Protocol. I'm using Cocoa Bindings , and Mutable Array for storing in it. The question is , I want to be able to have checkbox on each row, and select contacts that I want, and be able to get selected rows. How can I do it? When I try to put Check box cell in column of Table, nothing works. Here my code how I'm filling my NSTableView for contacts. So what should be done to be able add checkboxes and handle them? Thanks.
NSMutableDictionary *dict =[NSMutableDictionary dictionaryWithObjectsAndKeys:
Name, #"Name",
Surname, #"Surname",
Education,#"Education",
nil];
//controller for binding data to NSTableView
[controllerContacts addObject:dict];
//Table for viewing data.
[viewTableOfContacts reloadData];
If you want to use checkbox at each row via bindings, you need to define a key in dict corresponding to your binding for check box.
In your case, it can be like this-
NSMutableDictionary *dict =[NSMutableDictionary dictionaryWithObjectsAndKeys:
Name, #"Name",
Surname, #"Surname",
Education,#"Education",
[NSNumber numberWithInt:0],#"selectedStudent",
nil];
Then bind that column for "selectedStudent" key.
Also if you want to retrieve only selected rows, you can use NSPredicate like this-
NSPredicate *selectedStudentPredicate = [NSPredicate predicateWithFormat:#"selectedStudent == 1"];
NSArray *selectedStudents = [controllerContacts filteredArrayUsingPredicate:selectedStudentPredicate];
Hope this helps !