Class method returning empty array - objective-c

I have written a class method that converts columnar data from a text file and returns an array of arrays...only it is returning an EMPTY array of EMPTY arrays.
+(NSArray *) initArrayWithFileContents:(NSString *) theFilePath
{
NSString *theContents = [self loadFile:theFilePath];
NSArray *theParagraphs = [self getParagraphs:theContents];
NSMutableArray *teamData = [[NSMutableArray alloc] init]; // array of team data
NSMutableArray *leagueData = [[NSMutableArray alloc] init]; // array of arrays
// set up number formatters for getting numbers from strings
NSNumberFormatter *numberStyle = [[NSNumberFormatter alloc] init];
NSNumberFormatter *positiveNumberStyle = [[NSNumberFormatter alloc] init];
[numberStyle setNumberStyle:NSNumberFormatterDecimalStyle];
[positiveNumberStyle setNumberStyle:NSNumberFormatterDecimalStyle];
[positiveNumberStyle setPositiveFormat:#"'+'#"];
// set up a date and time formatter for getting time data from strings
NSDateFormatter *timeStyle = [[NSDateFormatter alloc] init];
[timeStyle setDateStyle:NSDateFormatterNoStyle];
[timeStyle setDateFormat:#" mm:ss"];
for (NSString *currentParagraph in theParagraphs)
{
NSArray *currentTeam = [self getcolumnarData:currentParagraph]; // get an array of strings
for (NSString *currentItem in currentTeam)
{
NSNumber *currentStat = [numberStyle numberFromString:currentItem];
if (currentStat != Nil) {
[teamData addObject:currentStat]; // number found
} else {
currentStat = [positiveNumberStyle numberFromString:currentItem];
if (currentStat != Nil) {
[teamData addObject:currentStat]; // number with '+' sign found
} else {
NSDate *currentTime = [timeStyle dateFromString:currentItem];
if (currentTime != Nil) {
NSNumber *theSeconds = [self calculateSeconds: currentTime];
[teamData addObject:theSeconds]; // time found
} else {
[teamData addObject:currentItem]; // string found
}
}
}
}
[leagueData addObject:teamData]; // add child array to end of parent array
[teamData removeAllObjects]; // reset child array
}
NSArray *dataToReturn = [NSArray arrayWithArray:leagueData]; // convert to NSArray to return
return dataToReturn;
}
In my debugging efforts I have verified that either an NSString or NSNumber is being added to the end of the teamData array but when adding teamData to leagueData an empty object is added. What am I missing?
Thanks in advance,
Brad

Move
NSMutableArray *teamData = [[NSMutableArray alloc] init];
into the loop:
for (NSString *currentParagraph in theParagraphs)
{
NSMutableArray *teamData = [[NSMutableArray alloc] init];
// ...
[leagueData addObject:teamData];
}
loop. At present, you always add the same array to leagueData.
An array "only" keeps pointers to its elements, so at the end all elements
of leagueData point to the same array teamData (from which you have removed
all objects).

Related

Unable to add multiple objects to NSArray [duplicate]

I'm trying to add objects to a NSMutableArray through a for loop. But it seems whenever I add an object it replaces the old one so that I only have one object in the array at the time...
Do you have any idea of what might be wrong?
- (void)viewDidLoad
{
[super viewDidLoad];
LoginInfo *info = [[LoginInfo alloc] init];
info.startPost = #"0";
info.numberOfPosts = #"10";
info.postType = #"1";
getResults = [backendService getAllPosts:info];
for (NSInteger i = 0; i < [getResults count]; i++) {
Post *postInfo = [[Post alloc] init];
postInfo = [getResults objectAtIndex:i];
dataArray = [[NSMutableArray alloc] init];
[dataArray addObject:postInfo.noteText];
NSLog(#"RESULT TEST %#", dataArray);
}
}
It's the RESULT TEST log that always shows only the last added string in the output.
you are initialising the dataArray inside the for loop, so everytime it is created again (which means there are no objects) and a new object is added
move
dataArray = [[NSMutableArray alloc] init];
to before the for loop
also there is no need to alloc/init the postInfo object when you immediately override it with the object from the getResults array
You keep re-initializing the array for every run of the loop with this line:
dataArray = [[NSMutableArray alloc] init];
So dataArray is set to a new (empty) array for every run of the loop.
Initialize the array before the loop instead. Try something like this:
dataArray = [[NSMutableArray alloc] init];
for (NSInteger i = 0; i < [getResults count]; i++) {
PostInfo *postInfo = [getResults objectAtIndex:i];
[dataArray addObject:postInfo.noteText];
NSLog(#"RESULT TEST %#", dataArray);
}

Convert a string to a positive or negative number

I am new to ObjC. I've spent years working in Applescript and I've decided to move up. I am a hobbiest programmer.
I have the following code:
+(NSArray *) initArrayWithFileContents:(NSString *) theFilePath
{
NSString *theContents = [(self) loadFile:theFilePath]; // returns the contents of a text file
NSArray *theParagraphs = [(self) getParagraphs:theContents]; // returns the contents as an array of paragraphs
NSMutableArray *teamData = [[NSMutableArray alloc] init]; // array of team data
NSMutableArray *leagueData = [[NSMutableArray alloc] init]; // array of arrays
NSNumberFormatter *numberStyle = [[NSNumberFormatter alloc] init];
[numberStyle setNumberStyle:NSNumberFormatterDecimalStyle];
for (NSString *currentParagraph in theParagraphs)
{
NSArray *currentTeam = [(self) getcolumnarData:currentParagraph];
for (NSString *currentItem in currentTeam)
{
NSNumber *currentStat = [numberStyle numberFromString:currentItem];
if (currentStat != Nil) {
[teamData addObject:currentStat];
} else {
[teamData addObject:currentItem];
}
}
[leagueData addObject:teamData];
[teamData removeAllObjects];
}
return leagueData;
}
This works fine for strings and for negative numbers, but a number preceded by a "+" sign is returned as a string. I figure I need to use a different number formatter style but I don't know what to use.
Thanks in advance,
Brad
NSNumberFormatter *numberStyle = [[NSNumberFormatter alloc] init];
[numberStyle setNumberStyle:NSNumberFormatterDecimalStyle];
[numberStyle setPositiveFormat:#"'+'#"] ;
or
NSNumberFormatter *numberStyle = [[NSNumberFormatter alloc] init];
[numberStyle setNumberStyle:NSNumberFormatterDecimalStyle];
[numberStyle setPositivePrefix:#"+"] ;
You could remove the + sign if one exists:
if ([currentItem hasPrefix:#"+"])
{
currentItem = [currentItem substringWithRange:NSMakeRange(1, [currentItem length] -1)];
}
Probably a better way, but this would work.
What ended up working for me was to create 2 NSNumberFormatters; 1 for decimals and 1 for decimals using the setPositiveFormat: method as described above. If the first formatter doesn't work, it'll flow on to the next formatter using the positive format.

addObject replaces previous object in NSMutableArray

I'm trying to add objects to a NSMutableArray through a for loop. But it seems whenever I add an object it replaces the old one so that I only have one object in the array at the time...
Do you have any idea of what might be wrong?
- (void)viewDidLoad
{
[super viewDidLoad];
LoginInfo *info = [[LoginInfo alloc] init];
info.startPost = #"0";
info.numberOfPosts = #"10";
info.postType = #"1";
getResults = [backendService getAllPosts:info];
for (NSInteger i = 0; i < [getResults count]; i++) {
Post *postInfo = [[Post alloc] init];
postInfo = [getResults objectAtIndex:i];
dataArray = [[NSMutableArray alloc] init];
[dataArray addObject:postInfo.noteText];
NSLog(#"RESULT TEST %#", dataArray);
}
}
It's the RESULT TEST log that always shows only the last added string in the output.
you are initialising the dataArray inside the for loop, so everytime it is created again (which means there are no objects) and a new object is added
move
dataArray = [[NSMutableArray alloc] init];
to before the for loop
also there is no need to alloc/init the postInfo object when you immediately override it with the object from the getResults array
You keep re-initializing the array for every run of the loop with this line:
dataArray = [[NSMutableArray alloc] init];
So dataArray is set to a new (empty) array for every run of the loop.
Initialize the array before the loop instead. Try something like this:
dataArray = [[NSMutableArray alloc] init];
for (NSInteger i = 0; i < [getResults count]; i++) {
PostInfo *postInfo = [getResults objectAtIndex:i];
[dataArray addObject:postInfo.noteText];
NSLog(#"RESULT TEST %#", dataArray);
}

Different Keys Point to Same Object(s) in NSMutableDictionary

I have a custom object called Person that among other things contains an NSString field called descriptor, which stores what sort of person that Person object is (angry, sad, wild, happy, morose, etc). All of my Person objects are in an NSMutableArray, but I would like to store them in an NSMutableDictionary in such a manner:
Key: A, Object: An NSMutableArray where all Person objects have descriptor starting with 'A'
Key: B, Object: An NSMutableArray where all Person objects have descriptor starting with 'B'
Key: C, Object: An NSMutableArray where all Person objects have descriptor starting with 'C'
etc...
I've tried to do this in my code below, and at the comment //POINT 1, the keys and arrays seem to match up, but at //POINT 2, when I print out the complete dictionary, all the keys come up with the same values!
So I wanted to know why the NSMutableArray I seem to have is not being stored as I want it in the NSMutableDictionary?
- (void)buildDictionaryForIndexList {
NSMutableDictionary *tempDict = [[[NSMutableDictionary alloc] init] autorelease];
NSMutableArray *personsStartingWithLetter = [[NSMutableArray alloc] init];
NSMutableArray *indexList = [[[NSMutableArray alloc] init] autorelease];
NSInteger loopCounter = 1;
NSString *firstLetter = [[[NSString alloc] init] autorelease];
for (Person *v in persons) {
firstLetter = [[v descriptor] substringWithRange:NSMakeRange(0, 1)];
if ([indexList containsObject:firstLetter]) {
[personsStartingWithLetter addObject:v];
if (loopCounter == [persons count]) {
[tempDict setObject:personsStartingWithLetter forKey:firstLetter];
}
} else {
if (loopCounter > 1) {
//POINT 1
NSLog(#"%#",[indexList objectAtIndex:[indexList count]-1]);
for (Person *q in personsStartingWithLetter) {
NSLog(#"%#",[q descriptor]);
}
[tempDict setObject:personsStartingWithLetter forKey:[indexList objectAtIndex:([indexList count] - 1)]];
[personsStartingWithLetter removeAllObjects];
}
[indexList addObject:firstLetter];
[personsStartingWithLetter addObject:v];
} // else
loopCounter++;
} // for
//POINT 2
NSEnumerator *enumerator = [tempDict keyEnumerator];
for (NSString *str in enumerator) {
NSLog(#"%#",str);
for (Person *c in [tempDict objectForKey:str]) {
NSLog(#"%#",[c descriptor]);
}
}
self.dictionary = tempDict;
} // buildDictionaryForIndexList
So, for example, at POINT 1 my output is:
A
Angry
Amiable
B
Belligerent
C
Cool
...
W
Wild
but at POINT 2 my output is
T
Wild
J
Wild
A
Wild
...
W
Wild
Change [tempDict setObject:personsStartingWithLetter forKey:[indexList objectAtIndex:([indexList count] - 1)]]; (just after point 1) to [tempDict setObject:[[personsStartingWithLetter copy] autorelease] forKey:[indexList objectAtIndex:([indexList count] - 1)]];. The problem is that NSDictionary copies the key, but retains the value. Therefore, if you add a mutable array to the dictionary and then change it, the array in the dictionary also changes. You need to create a non-mutable copy of the array to put in the dictionary.
The whole method is a bit overcomplicated.
- (void)buildDictionaryForIndexList
{
NSMutableDictionary *tempDict = [[[NSMutableDictionary alloc] init] autorelease];
for (Person *v in persons)
{
NSString* firstLetter = [[v descriptor] substringWithRange:NSMakeRange(0, 1)];
NSMutableArray* personsStartingWithLetter = tempDict [firstLetter];
if (personsStartingWithLetter == nil)
{
personsStartingWithLetter = [NSMutableArray array];
tempDict [firstLetter] = personsStartingWithLetter;
}
[personsStartingWithLetter addObject:v];
} // for
self.dictionary = tempDict;
}
You start with an empty dictionary that will contain arrays. For every person, you check whether there is a suitable array or not, and if there isn't one, you create it. So now there is an array for the person, so you add it to the array. That's all.

Fill NSMutableArray from another NsMutableArray

I have two classes indexViewController and flashCardQuestionViewController.
In the indexViewController i have table filled with an array.
Now i am getting some data from the database:
-(void)getMultipleChoiceAnswer
{
if(optionid!=nil)
[optionid removeAllObjects];
else
optionid = [[NSMutableArray alloc] init];
if(optionText!=nil)
[optionText removeAllObjects];
else
optionText = [[NSMutableArray alloc] init];
clsDatabase *clsDatabaseObject = [[clsDatabase alloc] init];
sqlite3_stmt *dataRows = [clsDatabaseObject getDataset:"select optionID,OptionText from flashCardMultipleAnswer where questionId=1"];
while(sqlite3_step(dataRows) == SQLITE_ROW)
{
[optionid addObject:[NSNumber numberWithInt:sqlite3_column_int(dataRows,0)]];
[optionText addObject:[NSString stringWithUTF8String:(char *)sqlite3_column_text(dataRows,1)]];
}
sqlite3_finalize(dataRows);
[clsDatabaseObject release];
}
and I am calling this method in the viewDidLoad method of the indexViewController.
Now I have another NSMutableArray in the flashCardQuestionViewController named listNoOfOptionsInQuestion.
I want to fill listNoOfOptionsInQuestion with objects from optionText array in indexViewController.
How can I do this?
There are a number of ways to copy arrays: you can either use -[NSArray copy] to get an immutable copy, or -[NSArray mutableCopy] for a mutable copy. Don't forget that copy adds a reference so you'll need a release or autorelease somewhere (if you're not using GC that is).
Alternatively, you can use -[NSMutableArray addObjectsFromArray:].
Given your example, it looks like you want to do something like this at the end:
[flashCardQuestionViewController setListNoOfOptionsInQuestion:optionText];
And then in FlashCardQuestionViewController, you want something like:
- (void)setListNoOfOptionsInQuestion:(NSArray *)options
{
if (options != listNoOfOptionsInQuestion) {
[listNoOfOptionsInQuestion release];
listNoOfOptionsInQuestion = [options mutableCopy];
}
}
Rahul,
Do you really need to have a completely different copy of the MutableArray in each object. Would it be possible to have both objects point to the same array? For instance:
ClassOne *one = [[ClassOne alloc] init];
ClassTwo *two = [[ClassTwo alloc] init];
// build mutable array mArray
// ...
one.objectArray = mArray;
two.objectArray = mArray;
Or do you need to make changes to the two arrays in different ways? The try this (as suggested by Chris above) :
ClassOne *one = [[ClassOne alloc] init];
ClassTwo *two = [[ClassTwo alloc] init];
// build mutable array mArray
// ...
one.objectArray = mArray;
two.objectArray = [mArray mutableCopy];
again, if this isn't what you need then you'll have to give us a more precise question or problem that we can identify.