Memory leak with returned NSMutableArray from function

半腔热情 提交于 2019-12-12 04:04:16

问题


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 retained 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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!