reading Autosave'd NSSortDescriptor's from NSTableView - macos

I have an application that display an array of objects in a 6 column NSTableView. The user can display the list via whichever column sort order they prefer. The NSTableView in the XIB file uses the autosave feature so that the sort order is preserved over application launches. All is working well.
There are times though when I want to know what the user's sort order preference is before this particular NSTableView get's loaded. I'd like to read those sort ordering preferences out of the Preferences file to sort the array according to their preference, but without having loaded from the XIB file that contains that NSTableView.
I can see the sort descriptors saved in my app's standardUserDefaults Preferences file. It's an array with 12 items in it (0-11) and the even numbered elements (0,2,4,6,8,10) are shown as Data and the odd numbered elements(1,3,5,7,9,11) are Boolean's.
The documentation says that NSSortDescriptor conforms to NSSecureCoding, but if I instantiate an NSKeyedUnarchiver with one of the Data elements, I get:
"non-keyed archive cannot be decoded by NSKeyedUnarchiver"
If I use an NSUnarchiver, I get:
"* End of archive encountered prematurely at 58"
In either case, the Boolean elements in the array are the "ascending" flag property of the NSSortDescriptor and so it wouldn't even be included if doing the above. So I guess I need to combine the 2 elements in some way to get a coded sort descriptor? Does anyone have an idea of how to decode the "autosaved" sort descriptors?

this solution worked for me: (please ignore all the ZSAsserts)
its a method in a subclass/category of NSTableView
-(void) zsSetTableLayoutFromAutosaveName:(NSString*) autosaveName{
// set initial sortDescriptors
int i = 0;
NSString* columnName = #"";
NSMutableArray* sortDescriptors = [NSMutableArray new];
for (id data in [[NSUserDefaults standardUserDefaults] valueForKey:[NSString stringWithFormat:#"NSTableView Sort Ordering %#",autosaveName]]) {
if (i%2 == 0) {
ZSAssert([data isKindOfClass:[NSData class]]);
columnName = [NSUnarchiver unarchiveObjectWithData:data];
}
else {
ZSAssert([data isKindOfClass:[NSNumber class]]);
BOOL ascending = [((NSNumber*) data) boolValue];
[sortDescriptors addObject:[NSSortDescriptor sortDescriptorWithKey:columnName ascending:ascending]];
}
i++;
}
[self setSortDescriptors:sortDescriptors];
// set intial hidden-state
for (NSData* data in [[NSUserDefaults standardUserDefaults] valueForKey:[NSString stringWithFormat:#"NSTableView Hidden Columns %#",autosaveName]]) {
ZSAssert([data isKindOfClass:[NSData class]]);
NSString* colName = [NSUnarchiver unarchiveObjectWithData:data];
ZSAssert([colName isKindOfClass:[NSString class]]);
NSTableColumn* tc = [self tableColumnWithIdentifier:columnName];
if (!tc.isHidden){
[tc setHidden:YES];
}
}
// set initial width
i = 0;
for (id data in [[NSUserDefaults standardUserDefaults] valueForKey:[NSString stringWithFormat:#"NSTableView Columns %#",autosaveName]]) {
if (i%2 == 0) {
ZSAssert([data isKindOfClass:[NSData class]]);
columnName = [NSUnarchiver unarchiveObjectWithData:data];
}
else {
ZSAssert([data isKindOfClass:[NSString class]]);
float width = ((NSString*) data).floatValue;
[[self tableColumnWithIdentifier:columnName] setWidth:width];
}
i++;
}
[self setAutosaveName:autosaveName]; // from now on, every change made to the table should be automatically persisted into user-defaults
[self setAutosaveTableColumns:YES];
}

Related

How to Reorder Cells Between Sections with NSFetchedResultsController

I have a table view that allows users to reorder cells between sections.
I have this, which works in a table with one section, but I can't figure out how to change this to work between sections...
-(void)tableView:(UITableView *)tableView
moveRowAtIndexPath:(NSIndexPath *)sourceIndexPath
toIndexPath:(NSIndexPath *)destinationIndexPath;
{
NSMutableArray *things = [[fetchedResultsController fetchedObjects] mutableCopy];
// Grab the item we're moving.
NSManagedObject *thing = [[self fetchedResultsController] objectAtIndexPath:sourceIndexPath];
// Remove the object we're moving from the array.
[things removeObject:thing];
// Now re-insert it at the destination.
[things insertObject:thing atIndex:[destinationIndexPath row]];
// All of the objects are now in their correct order. Update each
// object's displayOrder field by iterating through the array.
int i = 0;
for (NSManagedObject *mo in things)
{
[mo setValue:[NSNumber numberWithInt:i++] forKey:#"displayOrder"];
}
[managedObjectContext save:nil];
}
Please could anyone help?

Retrieving the data from the table in iphone

I have a table wherein every row contains a textfield.After i entertext in all the rows which are text fields i want to retrieve the data into an array.Can any one tell me the idea of retrieving the data from every row which are textfields?
I cannot believe you. Bad grammar and no research.
To get an array of all text fields, I would do:
NSArray *subviews = self.view.subviews;
NSMutableArray *textFelds = [[NSMutableArray alloc]init];
NSMutableArray *indexPaths = [[NSMutableArray alloc]init];
NSObject *obj;
for (obj in subviews) {
if ([obj class] == [UITextField class]) {
[textFields addObject:obj];
CGPoint location = obj.center;
    NSIndexPath *indexPath = [self.tableView indexPathForRowAtPoint:location];
[indexPaths addObject:indexPath];
}
}
It first gets all of the subviews of the main view, then determines if they are text fields. If they are textFields, it adds that to an array and also gets the indexPath.
I hope I have answered your question
You are having the details like, which row has text fields, which are not.
You can get this feature by using two different king of cells
static NSString *CellIdentifierNormal = #"Cell";
static NSString *CellIdentifierTF = #"Cell";
UITableViewCell *cell;
if(indexPath.row %2 == 0){ //Example
cell = (UITableViewCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifierNormal];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifierNormal] autorelease];
}
} else {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifierTF] autorelease];
TF *tf = [[TF alloc] init];
tf.tag = 10;
}
In Text field row case, should not use the dequeueReusableCellWithIdentifier it re uses the existing cells, so that the text fields data may corrupt [This will happen when your data rows size greater than the table size - height]
Whenever you want collect the data from TF's
Just run loop with number of rows in table, and check same condition as you are using in creating cell.
Access the cell, and TF from cell by using tag number [10] from TF get the text

Updating Checkboxes In NSTableView With A "Select All" Checkbox

I've been searching, reading, trying different approaches, etc. for the last couple weeks trying to solve this issue, but no luck... Any help is appreciated.
I have an NSTableView which uses my controller class as it's datasource, an NSMutableArray(validPropertyList) of NSDictionaries to be more exact. I have the dictionaries holding one NSNumber numberWithBool with a key of #"checkboxValue", and one NSString with a key of #"address". I initially set all the checkboxValues to YES.
for (int i =0; i<properties.count; i++) {
NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithObjectsAndKeys:[properties objectAtIndex:i],#"address",[NSNumber numberWithBool:YES],#"checkboxValue", nil];
[validPropertyList addObject:dict];
}
My table has 2 columns, whose identifiers correspond to the key names of my dictionaries.
In IB, I dragged over a Check Box Cell into the "checkboxValues" column. The required methods are below for the table.
-(NSInteger)numberOfRowsInTableView:(NSTableView *)tableView{
return [validPropertyList count];
}
-(id)tableView:(NSTableView *)tableView objectValueForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row{
NSString *identifier = [tableColumn identifier];
return [[validPropertyList objectAtIndex:row]valueForKey:identifier];
}
All of that works fine. The table loads a (selected)checkbox in the first column and my string object in the other one for each dictionary in my array.
I implemented the below method in order to handle the state changes of the checkboxes in the table...
-(void)tableView:(NSTableView *)tableView setObjectValue:(id)object forTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row{
NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithDictionary:[validPropertyList objectAtIndex:row]];
[dict setValue:object forKey:#"checkboxValue"];
[validPropertyList replaceObjectAtIndex:row withObject:dict];
// NSLog(#"val is now %#",[[validPropertyList objectAtIndex:row]valueForKey:#"checkboxValue"]);
}
This appears to work as well. Clicking on a checkbox visually changes it's state. It also updates the [NSNumber numberWithBool] value in my array as it should.
I have a checkbox outside of the table that I'm trying to use to either select all or deselect all of the checkboxes in the table. I have a bool variable(selectAllValue) in my class that is bound to the state of this checkbox, and this checkbox calls the action below...
- (IBAction)selectAll:(id)sender {
if (selectAllValue == YES) {
for (int i=0; i<[validPropertyList count]; i++) {
NSMutableDictionary *dict = [validPropertyList objectAtIndex:i];
[dict setValue:[NSNumber numberWithBool:YES] forKey:#"checkboxValue"];
[validPropertyList replaceObjectAtIndex:i withObject:dict];
}
}
else{
for (int i=0; i<[validPropertyList count]; i++) {
NSMutableDictionary *dict = [validPropertyList objectAtIndex:i];
[dict setValue:[NSNumber numberWithBool:NO] forKey:#"checkboxValue"];
[validPropertyList replaceObjectAtIndex:i withObject:dict];
NSLog(#"new value in array when should be no is: %#",[validPropertyList objectAtIndex:i]);
}
}
[tv reloadData];
}
This does set all of the values in my array to the correct values, and then I call the [tv reloadData] to update the table. It doesn't visually change the values of the checkboxes though. That's my problem.
I've tried adding checkboxes to my dictionary instead of NSNumbers, but no difference. I've tried binding the checkboxes in the table to the bool selectAllValue, but no difference.
I've read other posts on SO that relate to checkboxes in tables, but none of them really address this. Again, any help is greatly appreciated.
Please let me know if you need more information.
Thanks
Scott

IOS: searchbar in tableview

I am creating a searchbar in a tableview but I have problems with this method delegate because I fill the table view with array inside another array...I show my code:
- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText
{
ProgramAppDelegate *appDelegate = (ProgramAppDelegate *)[[UIApplication sharedApplication] delegate];
[tableData removeAllObjects];// remove all data that belongs to previous search
if([searchText isEqualToString:#""] || searchText==nil){
[myTableView reloadData];
return;
}
NSInteger counter = 0;
for(NSString *name in appDelegate.globalArray )
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc]init];
NSRange r = [name rangeOfString:searchText];
if(r.location != NSNotFound)
{
if(r.location== 0)//that is we are checking only the start of the names.
{
[tableData addObject:name];
}
}
counter++;
[pool release];
}
[myTableView reloadData];
}
You can see the code "for(NSString *name in appDelegate.globalArray )" it don't work because I fill the table view with elements of arrays inside this global array, I make an example
In a row of my table view there is a uitableviewcell and inside it there are four label;
I write these label with string of this globalArray but in this way:
[cell.label1 setText:[[appDelegate.globalArray objectAtIndex:indexPath.row]objectAtIndex:1]];
[cell.label2 setText:[[appDelegate.globalArray objectAtIndex:indexPath.row]objectAtIndex:2]];
[cell.label3 setText:[[appDelegate.globalArray objectAtIndex:indexPath.row]objectAtIndex:3]];
[cell.label4 setText:[[appDelegate.globalArray objectAtIndex:indexPath.row]objectAtIndex:4]];
then in delegate method for searchbar the code "for(NSString *name in appDelegate.globalArray )" don't work, How can I change my code?
** I DON'T SAY THAT I WANT TO CHECK ONLY LABEL1 FOR THE SEARCH
The problem here is that globalArray is an array of arrays. So the loop should be something like.
for(NSArray *rowArray in appDelegate.globalArray )
{
for ( NSString *name in rowArray ) {
// Do your processing here..
}
}
Using tableData
In your tableView:cellForRowAtIndexPath:, do this
[cell.label1 setText:[[tableData objectAtIndex:indexPath.row]objectAtIndex:1]];
[cell.label2 setText:[[tableData objectAtIndex:indexPath.row]objectAtIndex:2]];
[cell.label3 setText:[[tableData objectAtIndex:indexPath.row]objectAtIndex:3]];
[cell.label4 setText:[[tableData objectAtIndex:indexPath.row]objectAtIndex:4]];
In your numberOfSectionsInTableView:, return 1;
In your tableView:numberOfRowsInSection:, return [tableData count];
You should include a method that will reset the search data to the original content when the user stops searching.
- (void)resetSearchData {
// Get appDelegate first.
self.tableData = [NSArray arrayWithArray:appDelegate.globalArray];
}

NSRuleEditor: Criteria for new row

When I hit the "+" button on a row in NSRuleEditor, a new row is created. How can I take influence on the criteria used for that row.
It seems NSRuleEditor defaults to selecting the first criterion sequentially from the list of possible values. I would much rather have the new row match the row where the "+" was clicked.
I was able to fake it by subclassing a private method:
- (void)_addOptionFromSlice:(id)slice ofRowType:(unsigned int)type
{
int rowIndex = [(NSRuleEditorViewSlice*)slice rowIndex];
NSArray *criteriaForRow = [self criteriaForRow:rowIndex];
NSArray *displayValuesForRow = [self displayValuesForRow:rowIndex];
self.template = [NSArray arrayWithObjects:criteriaForRow, displayValuesForRow, nil];
[super _addOptionFromSlice:slice ofRowType:type];
}
- (void)insertRowAtIndex:(NSInteger)rowIndex withType:(NSRuleEditorRowType)rowType asSubrowOfRow:(NSInteger)parentRow animate:(BOOL)shouldAnimate
{
[super insertRowAtIndex:rowIndex withType:rowType asSubrowOfRow:parentRow animate:shouldAnimate];
NSArray *template = self.template;
if (template != nil) {
[self setCriteria:[template objectAtIndex:0] andDisplayValues:[template objectAtIndex:1] forRowAtIndex:rowIndex];
}
}

Resources