NSMutableArray addObject, unrecognized selector - iphone

I'm trying to create an array (States) of arrays (Cities). Whenever I try to add an item to my City array I get this error:
'NSInvalidArgumentException', reason: '*** +[NSMutableArray
addObject:]: unrecognized selector sent to class 0x303097a0
My code is as follows.
The line it errors on is
[currentCities addObject:city];
I'm sure I've got some Memory Management problem as I still don't understand it all that well. Was hoping someone could explain my mistake to me.
if (sqlite3_prepare_v2(db, sql, -1, &statement, NULL) == SQLITE_OK){
// We need to keep track of the state we are on
NSString *state = #"none";
NSMutableArray *currentCities = [NSMutableArray alloc];
// We "step" through the results - once for each row
while (sqlite3_step(statement) == SQLITE_ROW){
// The second parameter indicates the column index into the result set.
int primaryKey = sqlite3_column_int(statement, 0);
City *city = [[City alloc] initWithPrimaryKey:primaryKey database:db];
if (![state isEqualToString:city.state])
{
// We switched states
state = [[NSString alloc] initWithString:city.state];
// Add the old array to the states array
[self.states addObject:currentCities];
// set up a new cities array
currentCities = [NSMutableArray init];
}
[currentCities addObject:city];
[city release];
}
}

The lines:
// set up a new cities array
currentCities = [NSMutableArray init];
Should read:
// set up a new cities array
[currentCities init];
which should hopefully fix your problem. Instead of initializing your array, you're sending an init message to a class object, which doesn't do anything. Afterwards, you're currentCities pointer is still not initialized.
Even better would be to remove that line and change the 4th line such that you allocate and initialize all in one step:
NSMutableArray *currentCities = [[NSMutableArray alloc] init];

You need to call some sort of initializer on NSMutableArray, don't you? initWithCapacity, or something like that? Not sure what you get if you leave it off.
** Just tested it. Make it [[NSMutableArray alloc] init] and you will be fine.

It was initialization problem for me.
Had to change from
NSMutableArray *myArray = [NSMutableArray mutableCopy]; // not initialized. don't know why this even compiles
[myArray addObject:someObject]; // crashed
to
NSMutableArray *myArray = [NSMutableArray new]; // initialized!

Related

Objective-C and ARC: Why value stored to during its initialization is never read?

I'm using this code with ARC:
NSMutableDictionary *datesDict = [[NSMutableDictionary alloc]init];
NSMutableArray *datesArray = [[NSMutableArray alloc]init];
for (NSString *key in programsArray) {
datesArray = [_onDemandDictionary objectForKey:key];
NSMutableArray *newDates = [[NSMutableArray alloc]init];
int count;
for (count = 0; count <datesArray.count; count++) {
NSMutableDictionary *programsDict = [[NSMutableDictionary alloc]init];
programsDict = [datesArray objectAtIndex:count];
[newDates addObject:[programsDict objectForKey:#"date"]];
}
[datesDict setObject:newDates forKey:key];
}
But when I run the analyzer tool I'm getting value stored to (datesArray and programsDict) during its initialization is never read on lines:
NSMutableArray *datesArray = [[NSMutableArray alloc]init];
programsDict = [datesArray objectAtIndex:count];
Why is this happening how do I get hid of the warning?
Thank you!
The issue is you create a new NSMutableArray and assign it to datesArray at the beginning
NSMutableArray *datesArray = [[NSMutableArray alloc]init];
Then almost immediately after you assign a completely different value to datesArray with
datesArray = [_onDemandDictionary objectForKey:key];
I would just start with
NSMutableArray *datesArray = nil;
It's the same concept for programsDict.
On line 2, you create a new array datesArray.
Then, on line 6 (first line of the for loop), you set a new value to datesArray.
The compiler is just warning you that the line 2 has no effect, and that the code is bugged (in the sense it does not do what you expect).
True, the programsArray could be an empty array, and in this case you want datesArray to just be initialized to use it after the snippet you showed us, but it would be better to make this explicit.
For programsDict, it is even easier: you initialize it with ... alloc] init] then set it to an object of datesArray, making the first operation useless.
You are not using datesArray in your loop, you are simply assigning it values, So either take it nil array like
NSMutableArray* datesArray = nil;
or like
NSMutableArray *datesArray;
to remove waring .

Programme crashes when add dictionary to array?

I have a crash problem when I am trying to add object into array, I think I have problem with the way i create object and release it. But I am not quite sure cause I am still kinda weak with memory management
NSMutableDictionary *schools = [[NSMutableDictionary alloc] init];
[schools setObject:name forKey:kFavoriteSchoolName];
//load data is getting data from NSUserDefault which I save
NSMutableArray *loadedArray = [self loadData];
//if loadedarray has object in there, then continue adding schools to it or make new array
if([loadedArray count] > 0)
{
[loadedArray addObject:schools];
> // it crashes here
[schools release];
return loadedArray;
} else
{
//It will add the school to the array for the first time if there is nothing when it loaded.
NSMutableArray *tempArray = [[[NSMutableArray alloc] init] autorelease];
[tempArray addObject:schools];
[schools release];
return tempArray;
}
This function help add the school into favorite list. I cant add once, but it crashes when I add it again.
This is my code of loadData function
- (NSMutableArray *) loadData
{
   NSUserDefaults *userDefault = [NSUserDefaults standardUserDefaults];
   
   NSMutableArray *list = [userDefault objectForKey:kSchoolList];
   
   return list;
   
}
The log does not say anything but this: Thread 1: Program received signal "SGABRT"
when I first run the programme and add, it is fine, I add school again then only it crashes, crashes at [loadedArray addobject:schools];
Your code looks clear. The only white spot is the way you create array in [self loadData] method.
You mentioned that you restore it from NSUserDefaults. Probably you just return it by [[NSUserDefaults standardUserDefaults] objectForKey:#"schools"].
Since objectForKey: method returns id type object you don't get a warning telling that objectForKey: returns NSArray not NSMutableArray.
Just make something like this:
return [NSMutableArray arrayWithArray:[[NSUserDefaults standardUserDefaults] objectForKey:#"schools"]];
I hope I guessed your code right ;)
It would help if you put up the log, so we'll know what the crash actually is. I assume at some point you are storing values of tempArray into loaded. Try changing your code to this
NSMutableDictionary *schools = [[NSMutableDictionary alloc] init];
[schools setObject:name forKey:kFavoriteSchoolName];
//load data is getting data from NSUserDefault which I save
NSMutableArray *loadedArray = [[self loadData] retain];
//if loadedarray has object in there, then continue adding schools to it or make new array
if([loadedArray count] > 0)
{
if([loadedArray isKindOfClass:[NSMutableArray class]]) {
[loadedArray addObject:schools];
}
else {NSLog(#"Not a mutable array");}
> // it crashes here
[schools release];
return [loadedArray autorelease];
} else
{
[loadedArray release];
//It will add the school to the array for the first time if there is nothing when it loaded.
NSMutableArray *tempArray = [[[NSMutableArray alloc] init] autorelease];
[tempArray addObject:schools];
[schools release];
return tempArray;
}
I found out that you didn't initialize your array loadArray. You
cannot add any value to uninitialized NSMutableArray.
You need to start with initialization.
NSMutableArray *loadArray = [[NSMutableArray alloc]init];
Then populate data to your array
[loadArray addObjectsFromArray:[self loadData]];

Issue in adding dynamic cell in table view?

Please have a look on my code which i am using to add dynamic cells in my table view add run time. At did select of my table view i have called this method.
- (void) allServersFound
{
// called from delegate when bonjourservices has listings of machines:
NSArray *newPosts = [[NSArray alloc]initWithObjects:#"A", nil]; // NSArray of machine names;
NSMutableArray *tempArray = [[NSMutableArray alloc] initWithObjects: #"A",#"B",#"C",#"D", nil];
int i = 0;
for (NSArray *count in newPosts)
{
[tempArray addObject:[NSIndexPath indexPathForRow:i++ inSection:0]];
}
[[self tblHome] beginUpdates];
[[self tblHome] insertRowsAtIndexPaths:tempArray withRowAnimation:UITableViewRowAnimationNone];
[[self tblHome] endUpdates];
[tempArray release];
}
But this give me following Exception at run time:
* Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[NSIndexPath _fastCStringContents:]: unrecognized selector sent to instance 0x4e0e130
First you initialize your tempArray with strings like this:
NSMutableArray *tempArray = [[NSMutableArray alloc] initWithObjects: #"A",#"B",#"C",#"D", nil];
Then you add indexPaths like this:
[tempArray addObject:[NSIndexPath indexPathForRow:i++ inSection:0]];
so the array you pass to the insertRowsAtIndexPaths method contains both strings and indexPaths objects. I think this is the reason of the exception.
As others noted, your tempArray contains a mixture of NSString and NSIndexPath objects. This is the most obvious thing that you need to address before you do anything else. You can use [NSMutableArray array] class method for that (it's autoreleased, so you'll need to remove the call to [tempArray release] at the end of your method).
A less obvious thing is that the model of your UITableView must be updated before you call insertRowsAtIndexPaths, otherwise you would get another exception in a much less obvious place.
Your tmparray contains NSString values as well as the IndexPaths, try removing the NSStrings first.
Try replacing the line
NSMutableArray *tempArray = [[NSMutableArray alloc] initWithObjects: #"A",#"B",#"C",#"D", nil];
with the line
NSMutableArray *tempArray = [[NSMutableArray alloc] initWithObjects:nil];

memory mgmt problem in complex dictionary

I hate asking memory management questions - all the good answers
are variations on RTFM. But this one is stumping me.
I have a (relatively) complex dictionary in my model class,
where each key points to an array of arrays. I constantly add and delete
items to it, depending on state. Each "item" is an array.
- (void)addToDictionary:(NSNumber *)itemID {
// get what we need (associated array of arrays & key) from the incoming ID
NSArray *incomingArray = [self getArrayFromID:[itemID intValue]];
NSString *myKey = [incomingArray objectAtIndex:0];
NSMutableArray *myNewArray = [[NSMutableArray alloc] init];
// case 1: this key is not in the dictionary yet
if ([[myDict allKeys] containsObject:myKey] == NO) {
[myNewArray addObject:incomingArray];
[myDict setObject:myNewArray forKey:myKey];
// case 2: key already there; add new array to its array
} else {
myNewArray = [NSMutableArray arrayWithArray:[myDict objectForKey:myKey]];
[myNewArray addObject:incomingArray];
[myDict removeObjectForKey:myKey];
[myDict setObject:myNewArray forKey:myKey];
}
// why isn't this line working??
[myNewArray release];
}
My question is the last line. I allocated this array to help me
work with the dictionary, and now I don't need it any more.
But the program will crash if I release it, and work just fine
if I comment that line out. What am I missing?
TIA
In case two you don't own the returned array. So only release it in case 1. And don't create something you'll not use. The NSMutableArray pointer will get assigned to some other data in case 2, not the one you've allocated. So you can't release something you don't own.
- (void)addToDictionary:(NSNumber *)itemID {
NSArray *incomingArray = [self getArrayFromID:[itemID intValue]];
NSString *myKey = [incomingArray objectAtIndex:0];
NSMutableArray *myNewArray;
if ([[myDict allKeys] containsObject:myKey] == NO) {
// Create when you need it
myNewArray = [[NSMutableArray alloc] init];
[myNewArray addObject:incomingArray];
[myDict setObject:myNewArray forKey:myKey];
// release when you're done with it
[myNewArray release];
} else {
myNewArray = [NSMutableArray arrayWithArray:[myDict objectForKey:myKey]]; // you don't own it!
[myNewArray addObject:incomingArray];
[myDict removeObjectForKey:myKey];
[myDict setObject:myNewArray forKey:myKey];
}
// why isn't this line working??
//[myNewArray release];
// because in case 2 it's not pointing to the right memory
}
Hope it works,
ief2

Table crashes when sorting the data multiple times

I have a tableview with a navigationBar with a segmentedControl on the top of the view. I have set up the segmentedControl with buttons that sort the table by either "FirstName" or "LastName". It works perfectly the first 2-4 of times you press the sorting buttons, but then the app crashes.
The debugger and console seem to be of no help finding the source of the bug. Does anyone see any glaring mistakes in my code?
Here is my code below, let me know if you have any questions. Thanks!
- (IBAction)sortingSegmentAction:(id)sender{
NSString *keyToSortBy = [NSString alloc];
if([sender selectedSegmentIndex] == 0)
{
self.sortingSegmentActionPressed = 0;
keyToSortBy = #"FirstName";
}
else if([sender selectedSegmentIndex] == 1)
{
self.sortingSegmentActionPressed = 1;
keyToSortBy = #"LastName";
}
//Create the sort descriptors
NSSortDescriptor *sortDescriptor = [[[NSSortDescriptor alloc] initWithKey:keyToSortBy ascending:YES] autorelease];
NSArray *sortDescriptors = [NSArray arrayWithObject:sortDescriptor];
//Sort allSubItams by the values set in the sort descriptors
NSArray *sortedArray;
self.sortedArray = [allSubItems sortedArrayUsingDescriptors:sortDescriptors];
//Recreate the data structure by putting the newly sorted items into a dictionary sorted by inital letters.
NSDictionary *eachItemList; //A DICTIONARY FOR PUTTING ALL THE DATA FOR EACH ITEM IN IT'S OWN SECTION
NSMutableDictionary *tempSectionedDictionaryByFirstLetter = [[NSMutableDictionary alloc] init];
for (eachItemList in sortedArray) //eachElementList is a dictionary with a section for each item
{
NSDictionary *aDictionary = [[NSDictionary alloc] initWithDictionary:eachItemList];
NSString *firstLetterString;
firstLetterString = [[aDictionary valueForKey:keyToSortBy]substringToIndex:1];
NSMutableArray *existingArray;
if (existingArray = [tempSectionedDictionaryByFirstLetter valueForKey:firstLetterString])
{
[existingArray addObject:eachItemList];
} else {
NSMutableArray *tempArray = [NSMutableArray array];
[tempSectionedDictionaryByFirstLetter setObject:tempArray forKey:firstLetterString];
[tempArray addObject:eachItemList];
}
[aDictionary release];
[eachItemList release];
}
//Set the data source for the table (sectionedDictionaryByFirstLetter) to tempSectionedDictionaryByFirstLetter.
self.sectionedDictionaryByFirstLetter = tempSectionedDictionaryByFirstLetter;
NSMutableArray *keyArray = [[NSMutableArray alloc] init];
[keyArray addObjectsFromArray:[[self.sectionedDictionaryByFirstLetter allKeys] sortedArrayUsingSelector:#selector(compare:)]];
self.keys = keyArray;
[self.tableView reloadData];
[keyArray release];
[tempSectionedDictionaryByFirstLetter release];
}
Don't release eachItemList at the end of your loop. You did not explicitly allocate it in this context so you shouldn't release it.
The for (object in array) loop gives you a reference to the object in the array, not a copy. By sending a release message to this reference, you are decrementing the retain count of this object while it is still in the array. After a few times (depending on how many times the object has been retained, NSArray for example retains objects when they are added to the array) it's retain count will reach 0, and it will then become deallocated and you'll get crashes regarding unrecognised selectors or EXC_BAD_ACCESS and possibly other kinds of errors.