indexPath.row for whole tableview, not only section? - objective-c

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];

Related

Adding objects to array, array returning null

I have 2 arrays that receive information from a database. One, called json, contains posts with user id's and the other, called userJson, contains all the users with their id's. If the the user id from json equals a user id from userJson, I would like to populate a 3rd array with that users username. I am using the following code:
NSDictionary *info = [json objectAtIndex:indexPath.row];
NSDictionary *userInfo = [userArray objectAtIndex:0];
for (int i=0; i<[json count]; i++) {
if ([[userInfo objectForKey:#"user_id"] isEqualToString:[info objectForKey:#"user_id"]]) {
[usernameArray addObject:[userInfo objectForKey:#"username"]];
}
}
NSLog(#"%#", usernameArray);
usernameArray is the 3rd array that should contain the usernames. When I print it, it prints out null various times.
You need to first add this:
usernameArray = [[NSMutableArray alloc]init];
Then change your loop to the following:
NSDictionary *info = [json objectAtIndex:indexPath.row];
NSDictionary *userInfo;
for (int i=0; i<[userArray count]; i++) {
userInfo = [userArray objectAtIndex:i];
if ([[userInfo objectForKey:#"user_id"] isEqualToString:[info objectForKey:#"user_id"]]) {
[usernameArray addObject:[userInfo objectForKey:#"username"]];
}
}

Adding strings to an array in for loop and not overwrite the value in objective-c

I define a NSMutableArray *nameArray in .h file. And add strings using this nameArray in a for loop in .m file like below:
for (int i=0; i<[data count]; i++) {
NSDictionary* place = [data objectAtIndex:i];
NSString *name=[place objectForKey:#"name"];
_nameArray = [[NSMutableArray alloc] init];
[_nameArray addObject:name];
}
NSLog(#"After loop, Name is %#", _nameArray);
Actually, it should have several names in this array. But why it only output one name which was added in the array last?
You must create your array outside the loop, that is your problem.
// Init array
_nameArray = [[NSMutableArray alloc] init];
// Fill array
for (int i=0; i<[data count]; i++) {
NSDictionary* place = [data objectAtIndex:i];
NSString *name=[place objectForKey:#"name"];
[_nameArray addObject:name];
}
// Log array
NSLog(#"After loop, Name is %#", _nameArray);
All of your objects are added to an own array and only the last array will not be overwritten and is therefore in the log.

All objects in array (interpreted from csv) being returned as the same object (the last object)

What I am trying to achieve, is to convert a csv file into an array of custom objects, however, my attempts at this seem to result in all of the objects in the array being returned as the same object (the last object in the array).
Before I explain further, here is the code:
- (NSArray *)arrayFromCSVFileName:(NSString *)csvFileName fileType:(NSString *)fileType {
// Convert the file into an NSData object
NSString *studentFilePath = [[NSBundle mainBundle] pathForResource:csvFileName ofType:fileType];
NSData *studentData = [NSData dataWithContentsOfFile:studentFilePath];
// Convert the NSData into an NSString
NSString *csvString = [[NSString alloc] initWithData:studentData encoding:NSUTF8StringEncoding];
// Split each record (line) in the csvDataString into an individual array element (split on the newline character \n)
NSArray *csvArray = [csvString componentsSeparatedByString:#"\n"];
// Create an array to hold the parsed CSV data
NSMutableArray *parsedCSVArray = [[NSMutableArray alloc] init];
NSMutableArray *elementArray = [[NSMutableArray alloc] init];
CGSElement *elementToAdd = [[CGSElement alloc] init];
// Loop through each line of the file
for (int i = 0; i < [csvArray count]; i++) {
// Get a reference to this record (line) as a string, and remove any extranous new lines or alike
NSString *csvRecordString = [[csvArray objectAtIndex:i] stringByReplacingOccurrencesOfString:#"\r" withString:#""];
// Split the line by the comma delimeter
NSArray *csvRecordArray = [csvRecordString componentsSeparatedByString:#","];
// Check that there are actually fields (i.e. this is not a blank line)
if ( ([csvRecordArray count] > 0) && ([[csvRecordArray objectAtIndex:0] length] > 0) ) {
elementToAdd.mass = [[csvRecordArray objectAtIndex:1] floatValue];
elementToAdd.atomicNumber = [[csvRecordArray objectAtIndex:0] intValue];
elementToAdd.name = [csvRecordArray objectAtIndex:2];
elementToAdd.symbol = [csvRecordArray objectAtIndex:3];
elementToAdd.period = [[csvRecordArray objectAtIndex:4] intValue];
[elementArray addObject:elementToAdd];
}
}
for (int i = 0; i < [elementArray count]; i++) {
NSLog(#"%i", i);
CGSElement *current = [elementArray objectAtIndex:i];
NSLog(#"Name = %#", current.name);
}
// Return the parsed array
return elementArray;
}
The custom object in question is the CGSElement object, which I am attempting to fill the elementArray with. However, my debug code (the following section of code):
for (int i = 0; i < [elementArray count]; i++) {
NSLog(#"%i", i);
CGSElement *current = [elementArray objectAtIndex:i];
NSLog(#"Name = %#", current.name);
}
Is resulting, rather than in the return of all of the correct element names, it is returning the last element (to put this in context, ununoctium), 118 times.
After some testing, I can safely say that up until after this point:
elementToAdd.mass = [[csvRecordArray objectAtIndex:1] floatValue];
elementToAdd.atomicNumber = [[csvRecordArray objectAtIndex:0] intValue];
elementToAdd.name = [csvRecordArray objectAtIndex:2];
elementToAdd.symbol = [csvRecordArray objectAtIndex:3];
elementToAdd.period = [[csvRecordArray objectAtIndex:4] intValue];
All of the elements are being correctly defined, rather than just the same element over and over.
Needless to say, I'm stumped as to why it would be returning the same object over and over. Any help would be appreciated.
This line:
CGSElement *elementToAdd = [[CGSElement alloc] init];
Should be inside your loop, just before you try to edit the object and add it to the array. Currently you are repeatedly mutating the same object instead of creating new objects for each record.
You add the same entity all the time. It is crated once before the loop and within the loop it values are changed again and angan and it is added to the array. Naturally all items in the aray carry the same values because it is the same object.
If you want then change the array with an NSSet. To a set an object can only added once and you will end up with a set of 1. That is not the solution of couse, it would just visualize what is happening.
To solve it move this line
CGSElement *elementToAdd = [[CGSElement alloc] init];
to the beginning of the body of the for i loop, so that a new instance is created for every iteration and therefore for every index of the array.

Difficulty with getting random words from NSArray

When I Build & Run my application, it will not generate anything. What I have generating are words and after it erases that word and continues until it exhausts all the words and then repopulates the list again. Here is the code:
#implementation randomnumbersViewController
#synthesize words;
#synthesize randomArray;
#synthesize array;
-(IBAction)generateNumber:(id)sender {
NSInteger randomize(id num1, id num2, void *context);
int rand = arc4random() %2;
if (rand)
return NSOrderedAscending;
else
return NSOrderedDescending;
}
- (void)resetRandomArray;
{
[randomArray setArray: array];
[randomArray sortUsingFunction:random context:NULL];
}
- (NSString*) getRandomWord; {
if ([randomArray count] ==0)
return nil;
NSString* result;
NSInteger randomIndex = [[randomArray lastObject] intValue];
[randomArray removeLastObject];
result = [words objectAtIndex:randomIndex];
return result;
}
- (void)buildRandomWordArray
{
NSInteger index;
NSError *theError;
NSString *path = [[NSBundle mainBundle] pathForResource:#"words" ofType:#"text"];
NSString *text = [NSString stringWithContentsOfFile: path
encoding: NSUTF8StringEncoding
error: &theError];
self.words = [text componentsSeparatedByString: #"\n"];
int arraySize = [words count];
self.array = [NSMutableArray arrayWithCapacity:arraySize];
//This code fills "array' with index values from 0 to the number of elements in the "words" array.
for (index = 0; index<arraySize; index++)
[array addObject: [NSNumber numberWithInt: index]];
[self resetRandomArray];
//for (index = 0; index<=arraySize; index++)
// NSLog(# "Random word: %#", [self getRandomWord]);
}
Also a .txt document must be included in the resources folder in for this to work and I do have it there, but nothing. Does anyone have any suggestions as to how I can actually get it to generate the words, or why it isn't working properly?
I don't get how sorting the array ascending or descending is going to shuffle the array, maybe because it doesn't. :) You should use the Fisher–Yates shuffle implemented here: What's the Best Way to Shuffle an NSMutableArray? Import that category, and just call shuffle on the mutable array.

Dynamic population of a NSTableView with NSDictionaries with unknown keys

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];
}