Утечка на iPad, которую я не понимаю

У меня есть утечка в моем приложении, и я не знаю, почему. Может быть, я ошибся в управлении памятью. В моем коде у меня есть объект UIViewController, у которого есть ivar TelephoneValidator *validator

TelephoneValidator — это TelephoneValidator: NSObject

Итак, в моей функции инициализации объекта UIViewController (initWithFieldData) у меня есть:

-(id) initWithFieldData: (NSMutableDictionary*) fieldData
{
...
     validatorOptions     = [fieldData objectForKey:@"fieldValidator"];
...
}

Теперь, на мой взгляд,DidLoad у меня есть:

- (void)viewDidLoad {
...
if (![validatorOptions respondsToSelector:@selector(isEqualToString:)]) {

          validator = [[TelephoneValidator alloc] initWithOptions: validatorOptions];
     }
     else {
          validator = nil;
     }
...
}

По сути, если мой validatorOptions не равен NSString, ivar валидатора становится экземпляром TelephoneValidator.

В моем делелоке:

- (void)dealloc {

     if(validator != nil)
     {
          [validator release];
          validator = nil;
     }
...
[super dealloc];
    }

Я пару раз проверял, работает ли Dealloc, и это так. После вызова Dealloc валидатор освобождается (вызов любого метода валидатора после [выпуска валидатора] вызывает у меня исключение).

И все же в «Инструментах» мне говорят, что TelephoneValidator просочился. И после двойного щелчка в «Инструментах» выделена строка кода:

validator = [[TelephoneValidator alloc] initWithOptions: validatorOptions];

Что я делаю неправильно?

ОБНОВИТЬ:

Вот моя информация заголовка UIViewController:

@interface GenericViewController : UIViewController  <UITextFieldDelegate>{

UIImage *backgroundImage;
NSString *step; // na ktorym kroku jestesmy
id <GenericControllerDelegate> delegate; //delegata z ktorej bedziemy pobierali dane 
UITextField *textField;
NSString *fieldName; //nazwa pola (potrzebujemy zeby zapisac do modelu odpowiedni tekst
UILabel  *textLabel;
UILabel *stepsLabel;
UILabel *prefixTextLabel;

NSString *fieldPlaceholder;
NSString *textLabelText;
NSString *textLabelTextPl; //w jezyku polskim 
NSString *prefixTextLabelText; //w jezyku eng
NSString *prefixTextLabelTextPl; //w jezyku polskim prefix

NSString *fieldRequired;
NSString *keyboardType;
NSString *capitalizeType;

UIButton *button; //forward button
UIButton *button2;  //backward button

//to bedzie do przerobienia bo bedziemy mieli tablicje walidatorow a nie jeden walidator
NSString *validatorType;

//maksymalna dlugosc pola
int maxLengthOfTextField;

NSArray* validatorOptions;

TelephoneValidator *validator; 

//patientModel
PatientData *patientModel;

}

Заголовок TelephoneValidator:

#import <Foundation/Foundation.h>
#import "MAOTranslate.h"

@interface TelephoneValidator : NSObject {


    //opcje walidacyjne
    NSString *phonePrefix;
    NSString *phonePostfix;
    int       phoneLength;
    NSString *message;
    NSString *messagePl;

    UIAlertView *alertView;
}

-(id) initWithOptions:(NSArray *) optionsArray;

-(void) displayMessage;
-(BOOL) validate: (NSString *) phoneNumber;


@end

Класс TelephoneValidator:

#import "TelephoneValidator.h"


@implementation TelephoneValidator
//@synthesize phoneNumber;

-(id) initWithOptions:(NSArray *) optionsArray;
{
    if(self = [[TelephoneValidator alloc] init])
    {
        phonePrefix = [optionsArray objectAtIndex:0];
        phonePostfix = [optionsArray objectAtIndex:1];
        phoneLength = [[optionsArray objectAtIndex:2] intValue];
        message = [optionsArray objectAtIndex:3];
        messagePl = [optionsArray objectAtIndex:4];
    }
    else {
        self = nil;
    }

    return self;


}

//wyswietlamy wiadomosc
-(void) displayMessage
{
    NSString *displayMsg;
    if ([[MAOTranslate getLanguage] isEqualToString:@"pl"]) {
        displayMsg = messagePl;
    }
    else {
        displayMsg = message;
    }

    alertView = [[UIAlertView alloc] initWithTitle:@"Alert" message:displayMsg delegate:self cancelButtonTitle:@"ok" otherButtonTitles:nil];
    [alertView show];

}

-(BOOL) validate: (NSString *) phoneNumber
{


    //dlugosc
    if ([phoneNumber length] != phoneLength) {
        NSLog(@"zla dlugosc");
        return NO;
    }


    NSLog(@"tutaj");
    //sprawdzamy prefix     
    if ([phonePrefix length]!= 0) {     
        NSLog(@"w srodku ifa");
        if ([phoneNumber compare:phonePrefix options:NSLiteralSearch range:NSMakeRange(0, [phonePrefix length])] != 0) {
            NSLog(@"zly prefix");
            [self displayMessage];
            return NO;
        }
    }

    //sprawdzamy postfix
    if([phonePostfix length] != 0)
    {
        if ([phoneNumber compare:phonePostfix options:NSLiteralSearch range:NSMakeRange([phoneNumber length]-[phonePostfix length], [phonePostfix length])] != 0) {
            NSLog(@"zly postfix");
            [self displayMessage];
            return NO;
        }
    }


    //sprawdzamy czy string jest numeryczny

    NSCharacterSet *alphaNums = [NSCharacterSet decimalDigitCharacterSet];  
    NSCharacterSet *inStringSet = [NSCharacterSet characterSetWithCharactersInString:phoneNumber];  

    if (![alphaNums isSupersetOfSet:inStringSet]) 
    {
        NSLog(@"zly format ");
        [self displayMessage];
        return NO;
    }

    return YES; //zwalidowany poprawnie
}

-(void) dealloc
{   

    [alertView release];
    alertView = nil;
    [super dealloc];
}

person Ertai    schedule 04.01.2011    source источник
comment
Я думаю, что в этих частях кода нет ничего плохого, должно быть где-то еще.   -  person Bruno Domingues    schedule 04.01.2011
comment
Я тоже так думал, что здесь все в порядке. Тем не менее, Instruments продолжают настаивать на том, что утечка здесь. Мое приложение работает в контроллере навигации, поэтому я нажимаю свой UIViewController, и вот тогда у меня есть эта утечка. С чего начать поиск моего кода? Это единственное место, где я использую этот объект (TelephoneValidator).   -  person Ertai    schedule 04.01.2011
comment
[[TelephoneValidator alloc] initWithOptions: validatorOptions] что-нибудь сохраняет? Опубликуйте этот код.   -  person Stephen Furlani    schedule 04.01.2011
comment
Готово, я обновил основной вопрос.   -  person Ertai    schedule 04.01.2011


Ответы (3)


См. Эти обе строки

validator = [[TelephoneValidator alloc] initWithOptions: validatorOptions];

и внутри initWithOptions

if(self = [[TelephoneValidator alloc] init])

Вы выделяете вдвое больше валидатора, так что есть утечка.

person Bruno Domingues    schedule 04.01.2011

Вам нужно вызвать [super Dealloc] в конце метода Dealloc.

person willcodejavaforfood    schedule 04.01.2011

Может быть, инструменты указывают на validatorOptions как на источник утечки? Это сохраненная собственность, высвобождаемая в Dealloc или нет? Я не могу сказать наверняка, кода, который вы разместили, недостаточно, чтобы сделать вывод.

Кроме того, как говорит willcodejavaforfood, вы всегда должны вызывать [super dealloc]; в конце вашего метода Dealloc. Код не должен следовать после него.

Редактировать:

Я вернулся. Но Бруно Домингес уже понял правильно, вы выделяете дважды, и в этом случае происходит утечка первого. Вы должны изменить свой код -initWithOptions: на:

-(id) initWithOptions:(NSArray *) optionsArray;
{
    if((self = [super init])){
    // ... rest of code is fine
    }

    return self;
}
person Altealice    schedule 04.01.2011
comment
Я переместил [super Dealloc] в самый низ всего. Может быть, я не могу правильно пользоваться инструментами. Что я делаю: 1. Добираюсь до точки в моем приложении, где происходит утечка. 2. На вкладке «Утечка блоков» у меня есть TelephoneValidator (так что это не validatorOptions), затем некоторый адрес, затем количество байтов, затем имя моего приложения (как ответственная библиотека), затем ответственный кадр — это имя моего UIViewController. Теперь я дважды щелкаю текст TelephoneValidator, и я попадаю прямо в код, который я опубликовал. Я мог бы предоставить больше кода, но что именно вы подразумеваете под словом statint, что этого недостаточно? - person Ertai; 04.01.2011
comment
Вы используете инструменты в порядке. Я имел в виду, что недостаточно сделать вывод, что validatorOptions протекает. Вы проверили, действительно ли это объект, который протекает? Как вы объявили и где выпускаете validatorOptions? - person Altealice; 04.01.2011
comment
validatorOptions — это еще один ivar, и он устанавливается в initilizier: validatorOptions = [fieldData objectForKey:@fieldValidator] сначала у меня не было релиза для validatorOptions, но после вашего комментария я обновил свой Dealloc, и теперь есть [validatorOptions release]; Но утечка происходит, когда я создаю UIViewController (после viewDidLoad), а не когда я возвращаю его обратно. Я немного запутался, почему происходит утечка, когда вы только что создали объект? - person Ertai; 04.01.2011
comment
Если validatorOptions — это просто ivar (а не сохраненное свойство), вам следует добавить к нему retain, когда он назначается в init. objectForKey возвращает автоматически выпущенный объект. Добавьте retain в init и оставьте release в Dealloc. Является ли validator просто иваром, а не сохраненной собственностью? - person Altealice; 04.01.2011
comment
ivar = переменная экземпляра, верно? Я обновлю свой исходный пост, указав соответствующую информацию в заголовке. - person Ertai; 04.01.2011
comment
Комментарии на польском языке (мой родной язык), поэтому спрашивайте, если что-то неясно. - person Ertai; 04.01.2011
comment
В порядке. Попробую посмотреть на это через пару часов, мне сейчас нужно бежать домой. :) - person Altealice; 04.01.2011