Code:
// Build a section/row list from the alphabetically ordered word list
- (void) createSectionList
{
sectionArray = [[NSMutableArray alloc] init];
// Build an array with 26 sub-array sections
for (int i = 0; i < 26; i++) [sectionArray addObject:[[NSMutableArray alloc] init]];
// the line above will normally cause a leak
// Add each word to its alphabetical section
for (NSString *cities in listData)
{
if ([word length] == 0) continue;
// determine which letter starts the name
NSString *firstletter = [[word substringToIndex:1] uppercaseString];
NSRange range = [ALPHA rangeOfString:firstletter];
// Add the name to the proper array
[[sectionArray objectAtIndex:range.location] addObject:city];
}
}
It looks here like you're creating a 2-dimensional array by allocating one array (sectionArray), then allocating individual arrays as elements of that first array. On the offending line, the [[NSMutableArray alloc] init] returns instances with retaincount (rc) = 1, and adding it to the array makes rc=2. In your dealloc method, you release sectionArray, which automatically sends a release to all entries in the array, but that will only make rc=1 in those array objects, thus causing a leak.
You can fix this in at least two different ways. (1) Before you release sectionArray, you can iterate it and manually call release on each element, or (2) change the [[NSMutableArray alloc] init] in your code to [[[NSMutableArray alloc] init] autorelease]. (Note: I usually choose the latter approach, for reasons obvious.

)
Code:
- (void)dealloc
{
[super dealloc];
[sectionArray release];
// just a style note here - typically you clean up everything in your class BEFORE calling the [super dealloc]
}
Code:
- (NSMutableArray *)grabCitiesWorld:(NSString *)country
{
NSMutableArray *cities = [[NSMutableArray alloc] init];
NSString *path = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:@"CityData.sqlite"];
if (sqlite3_open([path UTF8String], &database) == SQLITE_OK) {
NSString *longsql = [NSString stringWithFormat:@"SELECT city FROM %@ where country = '%@' ORDER BY City", table, country];
const char *sql = [longsql UTF8String];
sqlite3_stmt *statement;
if (sqlite3_prepare_v2(database, sql, -1, &statement, NULL) == SQLITE_OK) {
while (sqlite3_step(statement) == SQLITE_ROW) {
NSString *cityname = [NSString stringWithUTF8String:(char *) sqlite3_column_text(statement, 0)];
[cities addObject:cityname];
}
}
// "Finalize" the statement - releases the resources associated with the statement.
sqlite3_finalize(statement);
} else {
// Even though the open failed, call close to properly clean up resources.
sqlite3_close(database);
NSAssert1(0, @"Failed to open database with message '%s'.", sqlite3_errmsg(database));
// Additional error handling, as appropriate...
}
sqlite3_close(database);
return cities;
[cities release];
// BIG problem here
}
Hopefully, the problem here is obvious now. You're returning from the function before the [cities release] executes, so the release is never done. In a function, once any return statement it hit, the function ends. Period.
But you're thinking that you've allocated an array in this function -- how do you return a valid array, yet clean it up properly? Like this:
Code:
return [cities autorelease];
This will return an array that the caller can use, but will automatically be released via the autorelease pool and not cause a leak.
Hopefully this helps. Let us know how things progress.