addObject replaces previous object in NSMutableArray - objective-c

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

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

NSMutableArray of NSMutableArrays

I want to create an NSMutableArray of NSMutableArrays. Below is the psuedo code:
NSMutableArray *mapcoords = [[NSMutableArray alloc] init];
NSMutableArray *clustercoords = [[NSMutableArray alloc] init];
while (!FINISHED)
{
for(int j = 1;j <= 4;j++)
{
x = arc4random_uniform(45);
[mapcoords addobject:[NSNumber numberWitInt:x]];
}
[clustercoords addobject:mapcoords];
[mapcoords removeAllObjects];
}
When I inspect the "clustercoords" array at the end of the loop, all of the objects contain the same values. I figured this must be because I am pointing to the same object (mapcoords) every time I add it to clustercoords.
I assume that I would need a different several different "mapcoords" arrays so that the objects in mapccords are unique. Is this the correct assumption? Is there another alternative?
Your assumption is correct. Move the declaration and creation of mapcoords inside the while loop.
NSMutableArray *clustercoords = [[NSMutableArray alloc] init];
while (!FINISHED) {
NSMutableArray *mapcoords = [[NSMutableArray alloc] init];
for(int j = 1; j <= 4; j++) {
u_int32_t x = arc4random_uniform(45);
[mapcoords addObject:#(x)];
}
[clustercoords addObject:mapcoords];
}

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.

releasing a NSMutableArray is causing EXC_BAD_ACCESS error

so when i try to run the following code, i end up with a EXC_BAD_ACCESS error. it happens when i try to release a NSMutableArray retrievedAnalysisDataList. the array is a list of retrievedAnalysisData objects. if i try to either release the data list or if i set up the init with an autorelease, i get the same result. i'm kinda guessing it has something to do with the sorting section of the code since i don't have this issue with the retrievedAnalysisIDarray.
any ideas?
if (tempDict != NULL)
{
NSMutableArray *retrievedAnalysisDataList = [[NSMutableArray alloc] init];
NSMutableArray *retrievedAnalysisIDarray = [[NSMutableArray alloc] init];
for (id key in tempDict)
{
retrievedAnalysisData = [[RetrievedAnalysisData alloc] init];
retrievedAnalysisData.createDate = [[tempDict objectForKey:key] objectForKey:#"createdate"];
retrievedAnalysisData.ID = [[tempDict objectForKey:key] objectForKey:#"id"];
retrievedAnalysisData.mode = [[tempDict objectForKey:key] objectForKey:#"mode"];
retrievedAnalysisData.name = [[tempDict objectForKey:key] objectForKey:#"name"];
retrievedAnalysisData.numZones = [[tempDict objectForKey:key] objectForKey:#"numzones"];
retrievedAnalysisData.srcImg = [[tempDict objectForKey:key] objectForKey:#"srcimg"];
retrievedAnalysisData.type = [[tempDict objectForKey:key] objectForKey:#"type"];
//NSLog(#"\n createDate: %# \n id: %# \n mode: %# \n name: %# \n numzone: %# \n srcimg: %# \n type: %#", retrievedAnalysisData.createDate, retrievedAnalysisData.ID, retrievedAnalysisData.mode, retrievedAnalysisData.name, retrievedAnalysisData.numZones, retrievedAnalysisData.srcImg, retrievedAnalysisData.type);
[retrievedAnalysisDataList addObject:retrievedAnalysisData];
[retrievedAnalysisData release];
}
NSSortDescriptor *sortDescriptor;
sortDescriptor = [[[NSSortDescriptor alloc] initWithKey:#"createDate" ascending:YES] autorelease];
NSArray *sortDescriptors = [NSArray arrayWithObject:sortDescriptor];
NSArray *sortedRetrievedAnalysisDataList;
sortedRetrievedAnalysisDataList = [retrievedAnalysisDataList sortedArrayUsingDescriptors:sortDescriptors];
int count = [sortedRetrievedAnalysisDataList count];
for (int i = 0; i < count; i++) {
retrievedAnalysisData = [[RetrievedAnalysisData alloc] init];
retrievedAnalysisData = [sortedRetrievedAnalysisDataList objectAtIndex:i];
[retrievedAnalysisIDarray addObject:retrievedAnalysisData.ID];
[retrievedAnalysisData release];
}
dataCenter.sortedRetrievedAnalysisDataList = sortedRetrievedAnalysisDataList;
dataCenter.retrievedAnalysisIDarray = retrievedAnalysisIDarray;
[retrievedAnalysisIDarray release];
[retrievedAnalysisDataList release];
dataCenter.isRetrieve = [NSNumber numberWithInt:1];
[activityIndicator stopAnimating];
[picker reloadAllComponents];
picker.hidden = FALSE;
pickerToolBar.hidden = FALSE;
toolBar.hidden = TRUE;
innerCircle.hidden = TRUE;
outerCircle.hidden = TRUE;
trackLabel.hidden = TRUE;
displayGPSLabel.hidden = TRUE;
}
Your problem lies in this section of code:
retrievedAnalysisData = [[RetrievedAnalysisData alloc] init];
retrievedAnalysisData = [sortedRetrievedAnalysisDataList objectAtIndex:i];
[retrievedAnalysisIDarray addObject:retrievedAnalysisData.ID];
[retrievedAnalysisData release];
The first line allocates a new RetrievedAnalysisData, but then the second throws that away (leaking it) and places an object fetched from the array in the retrievedAnalysisData variable instead. You don't own this object fetched from the array, and you don't take ownership by calling retain. So the release on the fourth line is incorrect, releasing an object that you do not own.
Then when you release your NSMutableArray, it tries to release the object again and you get a crash because the object is already released.
To fix it, get rid of the useless first line, and also get rid of the incorrect release.
Without knowing the memory management of all your properties, it’s hard to see exactly what’s going on. But take a look here:
for (int i = 0; i < count; i++) {
retrievedAnalysisData = [[RetrievedAnalysisData alloc] init];
retrievedAnalysisData = [sortedRetrievedAnalysisDataList objectAtIndex:i];
[retrievedAnalysisIDarray addObject:retrievedAnalysisData.ID];
[retrievedAnalysisData release];
}
You call -release on an autoreleased object (retrievedAnalysisData). Try this instead:
for (int i = 0; i < count; i++) {
retrievedAnalysisData = [sortedRetrievedAnalysisDataList objectAtIndex:i];
[retrievedAnalysisIDarray addObject:retrievedAnalysisData.ID];
}

Method Creates an Array with 11 objects, All Out of Scope, Unrecognized Selector Results

Okay, so, I'm doing a simple lookup. I have an array of NSString objects and a string to search for in the array's elements.
It all seems to work up until I try to add a match to a new mutable array made to hold the search results. The stringHolder variable gets the string, and resultsCollectorArray even get the right number of new elements, but each element is empty and "out of range". Here's the method:
#implementation NSArray (checkForString)
-(NSMutableArray *) checkForString: (NSString *) matchSought
{
long unsigned numberofArrayElements;
long unsigned loop = 0;
NSRange searchResults;
NSMutableArray * resultCollectorArray = [[NSMutableSet alloc] init];
id stringHolder;
numberofArrayElements = [self count];
while (loop < numberofArrayElements) {
searchResults.length = 0;
searchResults = [[self objectAtIndex: loop] rangeOfString: matchSought options:NSCaseInsensitiveSearch];
if (searchResults.length > 0) {
stringHolder = [self objectAtIndex: loop];
[resultCollectorArray addObject: stringHolder];
}
loop++;
}
return [resultCollectorArray autorelease];
}
Once we get back to the main portion of the program, I get an unrecognized selector sent to the mutable array that was supposed to receive the result of the method. Here's the main section:
#import <Foundation/Foundation.h>
#import "LookupInArray.h"
int main (int argc, const char * argv[])
{
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
NSString *testString = [[NSString alloc] initWithString: #"ab"];
NSMutableString * resultString = [[NSString alloc] init];
NSArray * theArray = [[NSArray alloc] initWithObjects: ..., nil]; // Actual code has the objects
NSMutableArray *resultArray = [[NSMutableArray alloc] init];
NSUInteger arrayCount = 0;
unsigned long loops = 0;
resultArray = [theArray checkForString: testString];
arrayCount = [resultArray count];
while (loops < arrayCount){
resultString = [resultArray objectAtIndex: loops]; // Here's where we get the unrecognized selector.
NSLog(#"%#", resultString);
loops++;
}
[pool drain]; // Also, I'll release the objects later. I just want to get what's above working first.
return 0;
}
I've searched the other answers (for hours now), but didn't seen anything that solved the issue.
Any and all help would be really appreciated.
And thanks beforehand.
NSMutableArray * resultCollectorArray = [[NSMutableSet alloc] init]; is so incorrect. You are creating a mutable set and assigning it to a mutable array.
You are getting unrecognized selector because objectAtIndex: is not a valid selector for NSMutableSet. Make that statement,
NSMutableArray * resultCollectorArray = [[NSMutableArray alloc] init];
A Better way
NSArray * filteredArray = [array filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:#"SELF contains[cd] %#", searchString]];
You can directly filter the array using predicates. This way you do this in a single step. :)