Класс с утечками памяти в инструментах - PullRequest
0 голосов
/ 01 марта 2012

У меня есть пара классов, функции которых выполняют операторы SQL для веб-службы для получения или установки данных в базе данных.

Работает нормально, но проблема в том, что когда я тестирую приборы / утечки, 90% утечек происходят из-за этих классов.

Не могли бы вы сказать мне, что я теряю?

Спасибо.

Вот код:

Где хранятся данные:

.h

@interface iSQLResult : NSObject {
    NSMutableArray *Records;
}
@property (nonatomic, assign) int CountX;
@property (nonatomic, assign) int CountY;
@property (nonatomic, retain) NSMutableArray *Columns;
@property (nonatomic, retain) NSMutableArray *Records;
@property (nonatomic, retain) NSMutableArray *FieldsNames;
@property (nonatomic, assign) int ErrorCode;
@property (nonatomic, retain) NSString *ErrorDescription;


-(void)addField:(NSString*)fieldName;
-(void)addRecord:(NSMutableArray*)items;
-(NSMutableArray *)getRecord:(int)y;
-(NSString*)getValue:(int) x posY:(int) y;
-(NSString*)getValueByName:(NSString *) colName posY:(int) y;
-(void)setValueByName:(NSString *) colName posY:(int) y value:(NSString *)value;
-(id) copyWithZone: (NSZone *) zone;
@end

.m

#import "iSQLResult.h"
#import <stdarg.h>

@implementation iSQLResult
@synthesize CountX;
@synthesize CountY;
@synthesize Columns;
@synthesize Records;
@synthesize FieldsNames;
@synthesize ErrorCode;
@synthesize ErrorDescription;

-(id)init
{
    self = [super init];

    if (self)
    {
        self.CountX =0;
        self.CountY =0;
        self.ErrorCode = 0;
        self.ErrorDescription = @"";

        self.FieldsNames = [NSMutableArray array];
        self.Columns = [NSMutableArray array];
        self.Records = [NSMutableArray array];

    }

    return self;
}
-(void)removeRecord:(int)index
{
    [self.Records removeObjectAtIndex:index];
    self.CountY = self.CountY - 1;
}
-(void)addField:(NSString*)fieldName
{
    [self.FieldsNames addObject:[NSString stringWithFormat:@"%@", fieldName]];
    self.CountX = self.CountX +1;
}
-(void)addRecord:(NSMutableArray*)items
{
    [self.Records addObject:items];
    self.CountY = self.CountY +1;
}
-(NSMutableArray *)getRecord:(int)y
{
    return [Records objectAtIndex:y];
}
-(NSString *)getValue:(int) x posY:(int)y
{
    return [[NSString stringWithFormat:@"%@", [[Records objectAtIndex:y] objectAtIndex:x]] copy];
}
-(NSString*)getValueByName:(NSString *) colName posY:(int) y
{
    int a=0;
    for (a=0;a<CountX;a++)
    {
        if ([[colName uppercaseString] isEqualToString:[[FieldsNames objectAtIndex:a] uppercaseString]])
        {
            return [[NSString stringWithFormat:@"%@", [[Records objectAtIndex:y] objectAtIndex:a]] copy];
        }
    }
    return @"";
}
-(void)setValueByName:(NSString *) colName posY:(int) y value:(NSString *)value
{
    int a=0;
    for (a=0;a<CountX;a++)
    {
        if ([[colName uppercaseString] isEqualToString:[[FieldsNames objectAtIndex:a] uppercaseString]])
        {
            [[Records objectAtIndex:y] replaceObjectAtIndex:a withObject:value];
        }
    }

}
-(void)dealloc
{
    [Columns release];
    [Records release];
    [FieldsNames release];
    [ErrorDescription release];

    [super dealloc];
}
-(id) copyWithZone: (NSZone *) zone
{
    iSQLResult *SQLRCopy = [[iSQLResult allocWithZone: zone] init];

    [SQLRCopy setCountX:self.CountX];
    [SQLRCopy setCountY:self.CountY];
    [SQLRCopy setRecords:[self.Records mutableCopyWithZone:zone]];
    [SQLRCopy setColumns:[self.Columns mutableCopyWithZone:zone]];
    [SQLRCopy setFieldsNames:[self.FieldsNames mutableCopyWithZone:zone]];
    [SQLRCopy setErrorCode:self.ErrorCode];
    [SQLRCopy setErrorDescription:[self.ErrorDescription copyWithZone:zone]];

    return SQLRCopy;
}
@end

Класс, который запрашивает данные для класса связи веб-службы и получает структуру xml:

.h

#import <Foundation/Foundation.h>
#import "iSQLResult.h"
#import "IM2_WebServiceComm.h"

@interface iSQL : NSObject <NSXMLParserDelegate> {

    iSQLResult *SQLR;
    IM2_WebServiceComm * WSC;

    NSXMLParser *xmlParser;
    BOOL Found;
    BOOL FieldsReaded;
    BOOL loadFieldsNow;
    BOOL loadErrNumNow;
    BOOL loadErrDesNow;
    NSString *chunksString;
    NSMutableArray *tempRecord;
}
@property (nonatomic, retain) NSString *URLConnection;
-(void)SQLReader:(NSString*)SQLString;
-(void)SQLExec:(NSString*)SQLString;
-(void)setURLConnection:(NSString *) WebSURL;
-(iSQLResult*) getSQLR;
-(void) parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName;
-(void) parser:(NSXMLParser *) parser foundCharacters:(NSString *)string;
-(void) parser:(NSXMLParser *) parser didStartElement:(NSString *) elementName namespaceURI:(NSString *) namespaceURI qualifiedName:(NSString *) qName attributes:(NSDictionary *) attributeDict;
@end

.m

#import "iSQL.h"
@implementation iSQL
@synthesize URLConnection;
- (iSQLResult*)getSQLR
{
    return [SQLR copy];
}
-(void)SQLExec:(NSString*)SQLString
{

    FieldsReaded = NO;
    Found = NO;
    loadFieldsNow = NO;

    if (SQLR)
    {
        [SQLR release];
        SQLR = nil;
    }


SQLR = [[iSQLResult alloc] init];

WSC = [[IM2_WebServiceComm alloc] init];
[WSC setURL:URLConnection];

NSString *theXML = [WSC callMethod:@"ExecNonQuery" sendInstruction:SQLString];

@try
{
    xmlParser = [[NSXMLParser alloc] initWithData:[theXML dataUsingEncoding:NSUTF8StringEncoding]];
    [xmlParser setDelegate: self];
    [xmlParser setShouldResolveExternalEntities:NO];
    if(![xmlParser parse])
    {
        NSLog(@"ERROR PARSING");
    }
    [xmlParser release];
}
@catch(NSException * ex) 
{
    NSLog(@"%@",[[ex reason] UTF8String]);
}
[WSC release];
}
-(void)SQLReader:(NSString*)SQLString
{

FieldsReaded = NO;
Found = NO;
loadFieldsNow = NO;

if (SQLR)
{
    [SQLR release];
    SQLR = nil;
}

SQLR = [[iSQLResult alloc] init];

WSC = [[IM2_WebServiceComm alloc] init];
[WSC setURL:URLConnection];

NSString *theXML = [WSC callMethod:@"ExecSQL" sendInstruction:SQLString];

@try
{
    xmlParser = [[NSXMLParser alloc] initWithData:[theXML dataUsingEncoding:NSUTF8StringEncoding]];
    [xmlParser setDelegate: self];
    [xmlParser setShouldResolveExternalEntities:NO];
    if(![xmlParser parse])
    {
        NSLog(@"ERROR PARSING");
    }
    [xmlParser release];
}
@catch(NSException * ex) 
{
    NSLog([NSString stringWithFormat:@"%@",[[ex reason] UTF8String]]);
}
[WSC release];
}

-(iSQLResult *)getSingleSQLR:(iSQLResult *)SQLSource usingRow:(int)y
{

iSQLResult *SQLRAux = [[[iSQLResult alloc]init]retain];

[SQLRAux setCountX:SQLSource.CountX];
[SQLRAux addRecord:[SQLSource getRecord:y]];
[SQLRAux setFieldsNames:SQLSource.FieldsNames];

return SQLRAux;

}

-(void)parser:(NSXMLParser *)parser parseErrorOccurred:(NSError *)parseError{
    NSLog(@"Error on XML Parse: %@", [parseError localizedDescription] );
}

//#pragma XML Parser Delegate Methods
-(void) parser:(NSXMLParser *) parser didStartElement:(NSString *) elementName namespaceURI:(NSString *) namespaceURI qualifiedName:(NSString *) qName attributes:(NSDictionary *) attributeDict 
{
    if (!chunksString)
{
    chunksString = [[NSString alloc] init];
}
chunksString = @"";
if ([elementName isEqualToString:@"ErrCode"])
{
    loadErrNumNow = YES;
}
if ([elementName isEqualToString:@"ErrDesc"])
{
    loadErrDesNow = YES;
}

if ([elementName isEqualToString:@"Table"])
{
    Found = YES;
    loadFieldsNow = NO;
    tempRecord = [[NSMutableArray alloc] init];
}

if (Found && ![elementName isEqualToString:@"Table"]) 
{
    loadFieldsNow = YES;
    if (!FieldsReaded)
    {
        [SQLR addField:elementName];
    }   
}
}

-(void) parser:(NSXMLParser *) parser foundCharacters:(NSString *)string
{
    chunksString = [chunksString stringByAppendingString:string]; 
}       

-(void) parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName 
{
NSString * finalString;
finalString = [NSString stringWithFormat:@"%@",chunksString];

if (loadErrNumNow)
{
    [SQLR setErrorCode:[finalString intValue] ];
    loadErrNumNow = NO;
}
if (loadErrDesNow)
{
    [SQLR setErrorDescription:finalString];
    loadErrDesNow = NO;
}           

if (Found)
{
    if (loadFieldsNow) 
    {
        [tempRecord addObject:finalString]; 
    }
}

if ([elementName isEqualToString:@"Table"])
{
    [SQLR addRecord:tempRecord];
    [tempRecord release];
    Found = NO;
    FieldsReaded = YES;
    loadFieldsNow = NO;

}
}

-(void)dealloc
{
    if (SQLR)
    { 
        [SQLR release];
        SQLR = nil;
    }

    [URLConnection release];

    [super dealloc];

}
@end

Это абсолютно ошибочный класс, потому что утечки, каждый доступ - это утечка: (

Любая помощь, пожалуйста?

1 Ответ

2 голосов
/ 01 марта 2012

Вот некоторые вещи, которые я замечаю:

- [iSQLResult copyWithZone:]

Вы отправляете результат mutableCopyWithZone: (который возвращает сохраненный объект) установщикам, которые снова сохраняют объект. Один из способов исправить это - автоматически выпустить копию:

[SQLRCopy setRecords:[[self.Records mutableCopyWithZone:zone] autorelease]]

- [iSQL SQLExec:] и - [iSQL SQLReader:]

ivars WSC и xmlPareser распределяются, затем освобождаются, но не устанавливаются в ноль. Это не утечка, но вы сохраняете ссылку на освобожденный объект. Если вы разыграете это, вы потерпите крах.

- [iSQL getSingleSQLR: usingRow:]

iSQLResult *SQLRAux = [[[iSQLResult alloc]init]retain];

Вы имели в виду авто-релиз вместо того, чтобы сохранять его там? (И если вы это сделали, разве вы не должны автоматически выпускать возврат в getSQLR для согласованности?)

- [Парсер iSQL: didStartElement: namespaceURI: квалифицированное имя: атрибуты:]

chunksString назначается (+1 сохранить), но позже в синтаксическом анализаторе: foundCharacters: вы теряете ссылку (т.е. пропускаете строку) и заменяете ее строкой с автоматическим освобождением.


Это все, что я замечаю от руки. Похоже, что вы пропускаете больше, чем просто эти объекты, поэтому я предполагаю, что вы пропускаете объекты iSQL и / или iSQLResult. Помните, что когда вы пропускаете объект, вы также пропускаете все, на что ссылаются эти объекты. Даже если эти классы не имеют утечек, если код, создающий экземпляры классов, не освобождает объекты должным образом, вы увидите, что все члены этих классов также имеют утечки. При устранении утечек всегда сначала ищите объекты «верхнего уровня».

...