问题
I'm having problems with the implementation of the memory management of objective c. I've reed several manuals, but i think that I'm loosing something.
I'm developing an application that uses a UITableView that is loaded with the results of a query;
-(NSMutableArray *)sqlReader:(NSString *)sqlString
{
NSMutableArray *sqlResult = [[[NSMutableArray alloc] init] autorelease];
NSMutableArray *sqlRow = [[NSMutableArray alloc] init];
sqlite3 *database;
int dataType;
int intResult;
int colCount;
int a;
if(sqlite3_open([databasePath UTF8String], &database) == SQLITE_OK)
{
const char *sqlStatement = [sqlString UTF8String];
sqlite3_stmt *compiledStatement;
if(sqlite3_prepare_v2(database, sqlStatement, -1, &compiledStatement, NULL) == SQLITE_OK)
{
[sqlResult removeAllObjects];
while(sqlite3_step(compiledStatement) == SQLITE_ROW)
{
//[sqlRow removeAllObjects];
sqlRow = [[NSMutableArray alloc] init];
colCount = sqlite3_data_count(compiledStatement);
for (a=0;a<colCount;a++)
{
dataType = sqlite3_column_type(compiledStatement, a);
if (dataType == SQLITE_INTEGER)
{
intResult = sqlite3_column_int(compiledStatement, a);
[sqlRow addObject:[NSString stringWithFormat:@"%d",intResult]];
}
else if (dataType == SQLITE_TEXT)
{
[sqlRow addObject:[NSString stringWithUTF8String:(char *)sqlite3_column_text(compiledStatement, a)]];
}
else if (dataType == SQLITE_BLOB)
{
NSData *dataForCachedImage = [[NSData alloc] initWithBytes:sqlite3_column_blob(compiledStatement, a) length: sqlite3_column_bytes(compiledStatement, a)];
[sqlRow addObject:[UIImage imageWithData:dataForCachedImage]];
[dataForCachedImage release];
}
}
[sqlResult addObject:sqlRow];
[sqlRow release];
}
return sqlResult;
}
}
return nil;
}
The class that contains this function is used from a different class that is where the delegate methods of UITableView are implemented.
In the UIViewController of this class:
in the .h file is declared:
NSMutableArray *loadedInfo;//will contain all query results
@property (nonatomic, retain) NSMutableArray *loadedInfo;
in implementation file .m
@synthesize loadedInfo;
- (void)viewDidLoad {
loadedInfo = [[NSMutableArray alloc] init];
//do other initializations
In other method is where loadedInfo is filled with the query results:
-(void)loadTemas
{
loadedInfo = [SQL sqlReader:@"SELECT * FROM TEMAS ORDER BY NOMBRETEMA;"];
//This returns an autoreleased NSMutableArray
[detail reloadData];
//This calls the delegate methods of UITableView
}
The following two methods are the delegate of UITableView and a method used to create the returned cell
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
if (searchMode == 0)
return [self setTemaCell:indexPath tableView:tableView];
else if (searchMode == 1)
return [self setItemCell:indexPath tableView:tableView];
}
#pragma mark Set Cell Functions
-(UITableViewCell *)setTemaCell:(NSIndexPath *)indexPath tableView:(UITableView *)tableView
{
UITableViewCell *customCell;
UIImageView *imgIcon;
UILabel *lblTitle;
customCell = [tableView dequeueReusableCellWithIdentifier:@"CellID"];
CGRect frame = CGRectMake(0, 0, 0, 20);
//if (!customCell)
//{
customCell = [[[UITableViewCell alloc] initWithFrame:frame reuseIdentifier:@"CellID"] autorelease];
//}
//customCell = [customCell initWithFrame:frame reuseIdentifier:@"CellID"];
customCell.selectionStyle = UITableViewCellSelectionStyleNone;
imgIcon = [[UIImageView alloc] initWithFrame:CGRectMake(10, 13, 64, 64)];
[imgIcon setImage:[self imageWithImage:[[loadedInfo objectAtIndex:indexPath.row] objectAtIndex:2] scaledToSize:CGSizeMake(64, 64)]];
//This is the line where I'm having an EXEC_BAD_ACCESS.
[customCell.contentView addSubview:imgIcon];
[imgIcon release];
imgIcon = nil;
lblTitle = [[[UILabel alloc] initWithFrame:CGRectMake(80, 30, 270, 20)] autorelease];
lblTitle.font = [UIFont systemFontOfSize:24.0];
lblTitle.textAlignment = UITextAlignmentLeft;
lblTitle.backgroundColor= [UIColor whiteColor];
lblTitle.textColor = [UIColor blackColor];
lblTitle.text = [[loadedInfo objectAtIndex:indexPath.row] objectAtIndex:1];
[lblTitle setAlpha:1];
[customCell.contentView addSubview:lblTitle];
[customCell setAlpha:1];
return customCell;
}
I've readed the Memory Management Programing guide and several posts where explain the rules. Well, if i follow the rules (When an object must be returned from a method, this have to be declared with autorelease) the app crashes but if I don't the app memory occupation is higher than 30 MB!
My target is create a function where
(NSMutableArray *)function_A
{
NSMutableArray *theArray = [[NSMutableArray alloc] init];
/fill the array
return [theArray autorelease];
}
Caller Class
in header declare an array
NSMutableArray *theArray;
in init function initialize the array
theArray = [[NSMutableArray alloc] init];
in fill function fill the array with returned array
theArray = [myclass function_A];
in diferent functions use this returned array
in dealloc function release the array.
Is this possible? How is the best way to implement this?
Any help will be apreciated.
回答1:
It looks like in your caller class you forget to release
the old theArray
object, and you should retain
it.
Easiest would be to declare theArray
in your caller class as a retain
ed property (or copied), and when setting, use the provided setter:
self.theArray = [myclass function_A];
which will invoke the correct memory management behaviour.
Don't forget to release
in dealloc
.
Returning an autoreleased object is fine and what one should expect with that method name.
来源:https://stackoverflow.com/questions/4266485/memory-leak-with-returned-nsmutablearray-from-function