【问题标题】:Leak on iPad that I don't understand我不明白的 iPad 上的泄漏
【发布时间】:2011-01-04 13:28:25
【问题描述】:

我的应用程序出现泄漏,我不知道为什么。也许我把所有的内存管理都弄错了。在我的代码中,我有 UIViewController 对象,它具有 ivar TelephoneValidator *validator

TelephoneValidator 是 TelephoneValidator : NSObject

所以在我的 UIViewController 对象 (initWithFieldData) 的初始化函数中,我得到了:

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

现在在我的 viewDidLoad 中我得到了:

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

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

基本上,如果我的验证器选项不是 NSString,验证器 ivar 就变成了 TelephoneValidator 实例。

在我的交易中:

- (void)dealloc {

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

我已经检查了几次 dealloc 是否有效,并且确实有效。在调用 dealloc 之后,验证器被释放(在 [validator release] 之​​后调用验证器上的任何方法都会出现异常)。

然而在 Instruments 中却告诉我 TelephoneValidator 被泄露了。在 Instruments 中双击后,突出显示的代码行是:

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];
}

【问题讨论】:

  • 我认为这部分代码没有问题,一定是其他地方。
  • 我也是这么认为的,这里没什么问题。尽管如此,Instruments 仍然坚持认为泄漏就在这里。我的应用程序在 Navigation Controller 中工作,所以我正在推动我的 UIViewController,这就是我遇到这个泄漏的时候。从哪里开始搜索我的代码?这是我唯一使用这个对象的地方(TelephoneValidator)。
  • [[TelephoneValidator alloc] initWithOptions: validatorOptions] 是否保留任何内容?发布该代码。
  • 完成,我已经更新了主要问题。

标签: objective-c xcode memory-leaks ipad


【解决方案1】:

需要在dealloc方法的最后调用[super dealloc]。

【讨论】:

    【解决方案2】:

    看到这两行

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

    在initWithOptions里面

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

    您分配了两倍的验证器,因此存在泄漏。

    【讨论】:

      【解决方案3】:

      仪器是否将validatorOptions 指向泄漏源?它是在 dealloc 释放的保留财产吗?我不能肯定地说,您发布的代码不足以得出结论。

      另外,正如 willcodejavaforfood 所说,您必须始终在您的 dealloc 方法结束时调用 [super dealloc];。后面不能有任何代码。

      编辑:

      我回来了。但是 Bruno Domingues 已经做对了,你分配了两次,在这种情况下,第一个泄漏。您应该将-initWithOptions: 代码更改为:

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

      【讨论】:

      • 我已将 [super dealloc] 移至所有内容的底部。也许我不能正确使用 Instruments。我正在做的是: 1. 到达我的应用程序中发生泄漏的地方。 2.在 Leaked Blocks 选项卡上,我有 TelephoneValidator(所以它不是 validatorOptions),然后是一些地址,然后是泄漏的字节数,然后是我的应用程序名称(作为负责的库),然后负责的框架是我的 UIViewController 的名称。现在我双击 TelephoneValidator 文本,它让我直接进入我发布的代码。我可以提供更多代码,但你所说的 statint 到底是什么意思,这还不够?
      • 您使用仪器很好。我的意思是仅仅得出validatorOptions 泄漏的结论是不够的。您是否检查过是否确实是泄漏的对象?你是如何声明的以及在哪里发布validatorOptions
      • validatorOptions 是另一个 ivar,它在 initilizier 中设置:validatorOptions = [fieldData objectForKey:@"fieldValidator"] 起初我没有发布 validatorOptions 但在您发表评论后,我更新了我的 dealloc现在有[validatorOptions release];但是当我创建 UIViewController(在 viewDidLoad 之后)时发生泄漏,而不是在我将其弹回时发生。我有点疑惑,为什么刚刚创建了一个对象就出现了泄漏?
      • 如果 validatorOptions 只是一个 ivar(不是保留属性),那么当它在 init 中分配时,您应该添加一个 retain 给它。 objectForKey 返回一个自动释放的对象。在 init 中添加 retain 并将 release 保留在 dealloc 中。 validator 也只是一个 ivar 而不是保留属性吗?
      • ivar = 实例变量对吗?我将使用相关的标题信息更新我的原始帖子。
      猜你喜欢
      • 2020-03-10
      • 2020-11-17
      • 2011-08-05
      • 1970-01-01
      • 1970-01-01
      • 2013-12-24
      • 1970-01-01
      • 1970-01-01
      • 2010-10-07
      相关资源
      最近更新 更多