Ранний вызов сделки по освобождению объекта iOS

Мое приложение дает сбой из-за чрезмерно выпущенного объекта, и я сузил его до раннего вызова Dealloc в пользовательском классе. Это вызывает сбой, связанный с NSMutableArray, который использует пользовательский класс, указанный ниже:

#import <Foundation/Foundation.h>

@interface GraphData : NSObject{
    NSInteger key;
    NSString *value;
}

@property (nonatomic, readwrite) NSInteger key;
@property (nonatomic, retain) NSString *value;

-(id)initWithPrimaryKey:(NSInteger) xid;
-(id)initWithName:(NSString *)n key:(NSInteger)i;

@end


#import "GraphData.h"

@implementation GraphData

@synthesize  key,value;

-(id)initWithPrimaryKey:(NSInteger) xid{
    //[super init];
    self=[super init];
    if (self){
    self.key = xid;
    self.value = @"";
    }
    return self;

}
-(id)initWithName:(NSString *)n key:(NSInteger)i{
    self=[super init];
    if (self){
    self.key = 0;
    self.value = n;
    }
    return self;

}
-(void)dealloc{
    NSLog(@"Say bye to %@, kids!", self);
    [value release], value = nil;
    [super dealloc];

}

@end

Как ни странно, я использую GraphData в другом классе, и он работает без проблем. В этом случае, однако, Dealloc вызывает непосредственно перед тем, как я синтезирую NSMutableArray свойство NewData; но после того, как я синтезировал его три раза.

-(NSMutableArray*)fillDataInArray:(NSInteger)keyphrase_id{
    NSLog(@"lsd");
    NSLog(@"Keyphrase_id:%d", keyphrase_id);

    NSDate *startdate = [self getDateForApplicationInstalled];
    NSDate *enddate = [NSDate date];

    NSString *dateString1=[[NSString alloc] initWithString: [fmt stringFromDate:startdate]];
    NSString *dateString2=[[NSString alloc] initWithString: [fmt stringFromDate:enddate]];

    NSMutableArray *newDataNew = [[NSMutableArray alloc]init];
    self.theNewData = newDataNew;
    [newDataNew release];


    selStmt = nil;


    // build select statement
    if (!selStmt)
    {
        const char *sql = "select distinct position, key_time from ranking where keyphrase_id = ? and key_time between ? and ? order by key_time";


        if (sqlite3_prepare_v2(database, sql, -1, &selStmt, NULL) != SQLITE_OK)
        {
            selStmt = nil;
        }

        NSInteger n = keyphrase_id;
        sqlite3_bind_int(selStmt, 1, n);

        sqlite3_bind_text(selStmt, 2, [dateString1 UTF8String] , -1, SQLITE_TRANSIENT);
        sqlite3_bind_text(selStmt, 3, [dateString2 UTF8String] , -1, SQLITE_TRANSIENT);

        NSLog(@"SQL query is: [%s]", sql);
    }
    if (!selStmt)
    {
        NSAssert1(0, @"Can't build SQL to read keyphrases [%s]", sqlite3_errmsg(database));
    }

    int ret;

    while ((ret=sqlite3_step(selStmt))==SQLITE_ROW) 
    { 
        GraphData *item = [[GraphData alloc]init];

        item.key = sqlite3_column_int(selStmt, 0);
        item.value = [NSString stringWithUTF8String:(char *)sqlite3_column_text(selStmt,1)];

        [self.theNewData addObject:item]; 

        [item release];
    }

    sqlite3_reset(selStmt); // reset (unbind) statement

    [dateString2 release];
    [dateString1 release];

    return theNewData;

}

Доступ к нему также осуществляется другим методом:

-(NSMutableArray *) getDataForCharts:(int)seriesIndex{
    NSLog(@"speed");

    NSDate *startdate = [self getDateForApplicationInstalled];
    NSDate *enddate = [NSDate date];


    NSString *dateString1=[[NSString alloc] initWithString: [fmt stringFromDate:startdate]];
    NSString *dateString2=[[NSString alloc] initWithString: [fmt stringFromDate:enddate]];


    NSMutableArray *newDataNew = [[NSMutableArray alloc]init];
    self.actionNoteData = newDataNew;
    [newDataNew release];


    selStmt = nil;


    // build select statement
    if (!selStmt)
    {

        const char *sql = "";



        if (seriesIndex == 4) sql = "select distinct 105 score, notes_date from notes where iscompleted =1 and domain_id = ? and notes_date between ? and ? order by notes_date";

        if (sqlite3_prepare_v2(database, sql, -1, &selStmt, NULL) != SQLITE_OK)
        {
            selStmt = nil;
        }


        NSInteger n = domain_id;
        sqlite3_bind_int(selStmt, 1, n);

        sqlite3_bind_text(selStmt, 2, [dateString1 UTF8String] , -1, SQLITE_TRANSIENT);
        sqlite3_bind_text(selStmt, 3, [dateString2 UTF8String] , -1, SQLITE_TRANSIENT);

        NSLog(@"SQL query is: [%s]", sql);
    }
    if (!selStmt)
    {
        NSAssert1(0, @"Can't build SQL to read keyphrases [%s]", sqlite3_errmsg(database));
    }

    // loop reading items from list
    int ret;

    while ((ret=sqlite3_step(selStmt))==SQLITE_ROW) 
    { 
        GraphData *item = [[GraphData alloc]init]; // create item

        item.key = sqlite3_column_int(selStmt, 0);
        item.value = [NSString stringWithUTF8String:(char *)sqlite3_column_text(selStmt,1)];

        NSLog(@"Key:%d", sqlite3_column_int(selStmt, 0));
        NSLog(@"Value:%s", sqlite3_column_text(selStmt,1));

        [self.actionNoteData addObject:item]; // add to list
        [item release]; // free item

    }


    sqlite3_reset(selStmt); // reset (unbind) statement

    [dateString2 release];
    [dateString1 release];
    return actionNoteData;

}

Зомби указывает на [я отпускаю]; но это точный оператор, вызываемый ранее, который не приводит к сбою.

if (index == 4) {
        dateComponents.day = ([dateComponents day] -1 ) + dataindex + 1;

        if (dataForPlotActionNote.count > dataindex) {

            if ([dataForPlotActionNote objectAtIndex:dataindex]) {
                GraphData *i = (GraphData *) [dataForPlotActionNote objectAtIndex:dataindex];
                NSDate *date = [[[NSDate alloc] init] autorelease]; 

                date =[fmt dateFromString:i.value];

                datapoint.xValue = date;//[cal dateFromComponents:dateComponents];
                datapoint.yValue = [NSNumber numberWithDouble:(i.key)];

                [i release];
            }
        }
    }

Что может привести к тому, что вызов Dealloc произойдет на полпути выполнения кода?

Может ли создание свойства GraphData и его сброс каждый раз помочь поддерживать его в рабочем состоянии достаточно долго?


person Jace    schedule 15.06.2012    source источник
comment
Как вы объявляете свойство value?   -  person Johan Kool    schedule 15.06.2012
comment
Интересный код, вероятно, находится везде, где вы объявляете, создаете и сохраняете объекты GraphData.   -  person Phillip Mills    schedule 15.06.2012
comment
Отредактированный выше вопрос с дополнительным кодом.   -  person Jace    schedule 15.06.2012
comment
Пожалуйста, покажите код @interface, где объявлены эти свойства.   -  person Chris Trahey    schedule 15.06.2012
comment
Следующим шагом на этом пути будет просмотр состояния массива-владельца, когда ваш объект освобожден (или прервите освобождение и просмотрите трассировку стека), но вместо того, чтобы размышлять о том, какие вещи перевыпускаются, вы можете попробовать запустить в разделе «Инструменты» с обнаружением зомби.   -  person Phillip Mills    schedule 15.06.2012
comment
оффтоп: не используйте точечную нотацию в методах инициализации и удаления: stackoverflow.com/a/5932733/644629 и stackoverflow.com/a/9086811/644629   -  person CarlJ    schedule 15.06.2012
comment
Я выполнил обнаружение зомби, он выделяет выпуск GraphData после того, как я выделил его так же, как я делал ранее для трех других его экземпляров. Вот это меня так сильно смущает. Добавлено больше кода.   -  person Jace    schedule 15.06.2012


Ответы (1)


Проблема [i release] имеет смысл. Когда вы получаете ссылку на объект, находящийся внутри dataForPlotActionNote, вы не увеличиваете его счетчик сохранения, поэтому вы также не должны его уменьшать.

Места, где вы используете [item release], отличаются тем, что вы создали эти объекты с помощью alloc и поэтому делаете их сохранение.

person Phillip Mills    schedule 16.06.2012
comment
Да, это имеет смысл. При добавлении элементов выделяется GraphData; при ссылке на них позже, однако это не так. Это странно, поскольку на другие массивы ссылаются точно так же, а перевыпущенный объект возникает только для dataForPlotActionNote. Я поиграюсь с ним и посмотрю, что я могу изменить. - person Jace; 18.06.2012
comment
Несколько изменений, и он работает отлично, без утечек. Спасибо, что посмотрели на мой вопрос и указали мне на это. Это отличный пример потенциальных ловушек, с которыми можно столкнуться при наследовании проекта за последний месяц разработки. - person Jace; 18.06.2012
comment
Кстати, команда Product-›Analyze часто может указать на подобные вещи. - person Phillip Mills; 18.06.2012