Dynamic population of a NSTableView with NSDictionaries with unknown keys - objective-c

Is there no "simple" way to bind an NSArray that contains NSDictionaries with unknown keys to a NSTableView?
What is the best approach to solve this "common" problem?
Coming from c#/asp.net it seems to be a really painful operation.
edit:
To clarify what the app is about: its a simple queryeditor that displays the result of the query in a tableview.
I have tried to follow this example: http://www.cocoabuilder.com/archive/cocoa/150245-dynamic-columns-in-nstableview.html
I use an object that implements the NSTableViewDataSource protocol.
When the user issues the first query, the result is displayed correctly. But the second query shows something strange: the columns are not removed correctly and are added to the existing ones, but not all.
In the method, that builds the table i use something like this:
NSArray *columns = [_resultTableView tableColumns];
if(columns && [columns count] > 0)
{
for( int i=0; i < [columns count]; i++)
{
NSTableColumn *col = [columns objectAtIndex:i];
NSLog(#"removing column: %#", [col identifier]);
[_resultTableView removeTableColumn:col];
}
}
NSDictionary *dict = [_resultTableDataSource.data objectAtIndex:0];
NSArray *keys = [[dict keyEnumerator] allObjects];
for( int i=0; i < [keys count]; i++)
{
NSTableColumn *column = [[NSTableColumn alloc] initWithIdentifier:[keys objectAtIndex:i]];
[column setEditable:NO];
[[column headerCell] setStringValue:[keys objectAtIndex:i]];
[_resultTableView addTableColumn:column];
}
[_resultTableView setDataSource:_resultTableDataSource];
[_resultTableView reloadData];
_resultTableDataSource.data is a NSMutableArray with NSMutableDictionary's as records.

Take a look at NSArrayController and configure the columns in Interface Builder. Then it's as easy as 1-2-3 ;)
Start here and read on in the NSArrayController description:
http://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/CocoaBindings/Concepts/CntrlContent.html

Ok simple enough.
Since i iterate over the columns by reference i have to use 0 as index, since after the removal of the first column, the column count is already minus 1.
Changing the loop to the following solves the problem:
for( int i=0; i < [columns count]; i++)
{
NSTableColumn *col = [columns objectAtIndex:0];
NSLog(#"removing column: %#", [col identifier]);
[_resultTableView removeTableColumn:col];
}

Related

How to add elements in NSArray in Objective-C?

I want to add multiple elements in NSArray with #"title" and value.
for(int i = 0; i < size; i++){
BSDevice *d=[[DeviceManager devices] objectAtIndex:i];
self.dataArray =#[#{#"title":d.Name}];
}
But in this code it only adds one value. When I try with this method it doesn't work:
for(int i = 0; i < size; i++){
BSDevice *d=[[DeviceManager devices] objectAtIndex:i];
[self.dataArray addObject:#[#{#"title":d.buddyName}]];
}
I want to have multiple values with string and its value in NSArray like this #"title":d.Name,#"title":d.Name,#"title":d.Name
Your question isn't very clear and you didn't really explain what problem you are having with the second bit of code, but I think what you want is the following:
for (BSDevice *d in [DeviceManager devices]) {
[self.dataArray addObject:#{ #"title" : d.buddyName }];
}
This assumes that self.dataArray is an NSMutableArray and somewhere before this for loop you initialized self.dataArray as:
self.dataArray = [NSMutableArray array];

Why does replaceObjectAtIndex depend on whether or not I use a new definition in the loop?

I have two codes. Not working is the following:
NSMutableArray *tmpArray = [[NSMutableArray alloc] init];
for (int i=0; i<[dataSetArray count]; i++) {
tmpArray = (NSMutableArray *) [dataSetArray objectAtIndex:i];
// OR use: tmpArray = dataSetArray[i]
... doing stuff
[tmpArray replaceObjectAtIndex:0 withObject:tmpStr];
}
While this works:
for (int i=0; i<[dataSetArray count]; i++) {
NSMutableArray *tmpArray = [[NSMutableArray alloc] initWithArray:[dataSetArray objectAtIndex:i]];
... doing stuff
[tmpArray replaceObjectAtIndex:0 withObject:tmpStr];
}
Two questions:
The first code doesn't yield an NSMutableArray. Why? I declare it
above.
Is there a better way to obtain the same result. I just
dislike defining variables in a loop. This makes the code
unreadable.
--- edit:
Here the full code:
Datatypes are:
dataSetArray: NSMutableArray. However, its contents (i.e. dataSetArray[i]) are NSArrays (I read them into the program from an excel file).
NSString *tmpStr = [[NSString alloc] init];
for (int i=0; i<[dataSetArray count]; i++) {
NSMutableArray *tmpArray = [[NSMutableArray alloc] initWithArray:[dataSetArray objectAtIndex:i]];
for (int j=0; j<[tmpArray count]; j++) {
if ( [dataSetArray[0][j] isEqualToString:#"Number"] ) {continue;}
tmpStr = (NSString *) [tmpArray objectAtIndex:j];
// replace single backslash by double-backslash:
tmpStr = [tmpStr stringByReplacingOccurrencesOfString:#"\\" withString:#"\\\\"];
// replace first dollar sign by "<p>\\[" and second by "\\]</p>"
// Use a methode defined in the NSString+Extension
tmpStr = [tmpStr replaceTexFormulaSigns:tmpStr];
//NSLog(#"j=%d", j);
//NSLog(#"tmpArray is of type: %#", [tmpArray class]);
//NSLog(#" tmpStr is of type: %#", [tmpStr class]);
[tmpArray replaceObjectAtIndex:j withObject:tmpStr];
}
[dataSetArray replaceObjectAtIndex:i withObject:tmpArray];
}
So even if I use your suggestion, I am still facing the same problem with the inner array.
The first code doesn't yield a NSMutableArray. Why? I declare it above.
The declaration of the reference variable tmpArray does not change the type of the referred object. It is still an (immutable) array.
The creation of the mutable array at the very beginning of the first snippet is without any meaning, because the reference to it is overridden.
Is there a better way to obtain the same result. I just dislike defining variables in a loop. This makes the code unreadable.
Yes. The second example works in a way, but do something completely different. (It always creates a new array with a single item in it. No, that's not true. It shouldn't compile at all.)
You should do:
NSMutableArray *tmpArray = [dataSetArray mutableCopy];
for (int i=0; i<[dataSetArray count]; i++)
{
…
[tmpArray replaceObjectAtIndex:i withObject:tmpStr];
}
You should really get some additional knowledge about objects and object references.

indexPath.row for whole tableview, not only section?

I have a tableView wich displays content from an array with objects. But the tableview have sections for each date, and I get the same content in all the sections. I guess NSDictionary *object = [array objectAtIndex:indexPath.row]; returns the row for the section and not for the total array. How can I get the row count for the whole tableView? Or is it some other way to do it?
int rowsOffset = 0;
for (int section; section ++; section < indexPath.section) {
rowsOffset += [[[titles objectAtIndex:section] objectForKey:#"Values"] count];
}
NSDictionary *object = [array objectAtIndex:indexPath.row+rowOffset];
probably better:
NSArray *theArray = [[titles objectAtIndex:indexPath.section] objectForKey:#"Values"];
NSDictionary *object = [theArray objectAtIndex:indexPath.row];

How to set image for UIImageView which is contained in NSMutableArray?

I have NSMutableArray containing UIImageViews and NSArray containing UIImages. The arrays are of equal size. I need to set images from the second array to the first one. It would be very convinient to implement it in loop, something like:
for (int i = 0;i < firstArray.count;i++)
[firstArray objectAtIndex:i].image = [secondArray objectAtIndex:i];
but that doesn't compile. It says "Property "image" not found on object of type "id". Is it possible to implement it in loop somehow?
You need to cast from the id type to a UIImageView before accessing properties on it. Use the following...
for (int i = 0;i < firstArray.count;i++)
((UIImageView *)[firstArray objectAtIndex:i]).image = [secondArray objectAtIndex:i];
Alternatively if adding all of those round brackets makes it harder to read, (personally it draws my eye too much) you can do:
UIImageView *imageView = nil;
for (int i = 0;i < firstArray.count;i++) {
imageView = [firstArray objectAtIndex:i];
imageView.image = [secondArray objectAtIndex:i];
}
OR
for (int i = 0;i < firstArray.count;i++)
[[firstArray objectAtIndex:i] setImage:[secondArray objectAtIndex:i]];

How to generate an array of integers for use in a UIPickerView?

I'm using a UIPickerView and I want to load in a range of numbers to be displayed by the picker so I figured I'd use an NSMutableArray. I have two components in the picker view so I want to generate two different array's. I am generating my first array like this,
NSMutableArray *array1 = [NSMutableArray arrayWithCapacity:401];
for (int i=420; i>=20; i--) {
[array1 addObject:[NSString stringWithFormat:#"%d", i]];
}
self.myArray1 = array1;
This is working fine HOWEVER when I try generating my second array my app is crashing with no output to the console. The second array is being generated like this,
NSMutableArray *array2 = [NSMutableArray arrayWithCapacity:11];
for (int j=0; j<=10; j--) {
[array2 addObject:[NSString stringWithFormat:#"%d", j]];
}
self.myArray2 = array2;
What could I be doing wrong??
UPDATE:
Just want to add that I've tried creating these array's in both the init method of my class and the view didLoad method
j-- should be j++ as you are looping j from 0 to 10.