Obj-C, потенциальная утечка объекта, выделенного в строке, предупреждение?

#objective-c #xcode #cocoa-touch #analyzer

#objective-c #xcode #cocoa-touch #анализатор

Вопрос:

Я объявил следующую переменную как переменную экземпляра и использую ее в своем m-файле, однако я получаю предупреждение.

 TransparentToolbar *tools;
  

Потенциальная утечка объекта, выделенного в строке…

Например, я пытался создать для него свойство..

 @property (nonatomic, retain) TransparentToolbar *tools;
  

И синтезирую и освобождаю его, но мой просмотр завершается сбоем в конце dealloc.

Что я делаю не так?

ОТРЕДАКТИРУЙТЕ то же предупреждение в pickerSortingDataCurrent …

 h
@interface myViewController : UIViewController <UIActionSheetDelegate, 
    UIPickerViewDelegate, UIPickerViewDataSource, UITableViewDelegate, 
    UITableViewDataSource, MFMailComposeViewControllerDelegate> {

    TransparentToolbar *tools;

    NSArray *pickerSortingDataCurrent;
}
@property (nonatomic, retain) TransparentToolbar *tools;
@property (nonatomic, retain) NSArray *pickerSortingDataCurrent;

m
@synthesize pickerSortingDataCurrent;
@synthesize tools;

- (void)viewDidLoad {
    [super viewDidLoad];

    tools = [[[TransparentToolbar alloc] 
           initWithFrame:CGRectMake(0, 0, 70, 44.01)] autorelease];
    tools.barStyle = UIBarStyleBlackOpaque;

    self.pickerSortingDataCurrent = [[NSArray alloc] initWithObjects:
      @"Next Date Ascending", 
      @"Next Date Descending", nil];     // removed some items here
}

- (void)dealloc {
    [tools release];
    [pickerSortingDataCurrent release];
    [super dealloc];
}
  

Ааааа, у меня автоматический выпуск…. но это не решает проблему pickerSortingDataCurrent …

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

 #import "TransparentToolbar.h"

@implementation TransparentToolbar

- (void)drawRect:(CGRect)rect {
    // do nothing in here
}

- (void) applyTranslucentBackground
{
    self.backgroundColor = [UIColor clearColor];
    self.opaque = NO;
    self.translucent = YES;
}

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

// Override initWithFrame.
- (id) initWithFrame:(CGRect) frame
{
    self = [super initWithFrame:frame];
    [self applyTranslucentBackground];
    return self;
}

@end
  

ДАЛЬНЕЙШЕЕ РЕДАКТИРОВАНИЕ
введите описание изображения здесь

Комментарии:

1. Трудно сказать без кода.

2. Не могли бы вы включить свой dealloc код?

3. Я получаю ту же проблему с массивом данных интерфейса, который я заполняю в viewDidLoad, см. Редактирование выше.

4. чем больше информации вы предоставляете, тем проще нам вам помочь. например, как использовать вашу собственность? освобождение, определенное в TransparentToolbar и т.д.

5. @Anders K, смотри класс TransparentToolbar выше

Ответ №1:

Если вы определяете @property , то обычно при каждом обращении к ivar в вашем классе вы используете средство получения / установки, будь то точечная нотация или стандартный вызов метода.

Точечная нотация

 id localyMyVar = self.myVar;
self.myVar = @"A string";
  

Вызов стандартного метода

 id localMyVar = [self myVar];
[self setMyVar:@"A string"];
  

Если вы всегда явно используете эти методы получения и установки, то вам практически не нужно вызывать release где-либо в вашем коде, кроме dealloc или переопределенного setMyVar: метода. Выполнение этого таким образом позволяет управлять памятью в ограниченных местах. Если вы начнете освобождать и сохранять себя, то при первом запуске все может быть немного сложнее.

Обновить

@bbum дает вам ответ, но я думаю, что вам также было бы полезно быть более последовательным в вашем кодировании.

Например, перед строкой-нарушителем вы присваиваете значение непосредственно ivar без использования установщика. Будьте последовательны и используйте средство установки / получения, на синтез которого вы потратили время. Я бы переписал

 tools = [[[TransparentToolbar alloc] 
       initWithFrame:CGRectMake(0, 0, 70, 44.01)] autorelease];
tools.barStyle = UIBarStyleBlackOpaque;
  

Для

 TransparentToolbar *tmpTools = [[TransparentToolbar alloc] initWithFrame:CGRectMake(0, 0, 70, 44.01)];
tmpTools.barStyle = UIBarStyleBlackOpaque;
self.tools = tmpTools;
[tmpTools release]; tmpTools = nil;
  

Ваши init методы на самом деле не соответствуют рекомендациям, вы также должны проверять, что self действительно установлено, поэтому это должно выглядеть примерно так:

 - (id)init
{
    self = [super init];
    if (self) {
        [self applyTranslucentBackground];
    }
    return self;
}
  

Обновить

Утечка памяти, которую вы видите здесь:

 self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithCustomView:self.tools];
  

это потому, что вы просматриваете документы для UINavigationItem, вы увидите, что rightBarButtonItem он объявлен как retain

 @property(nonatomic, retain) UIBarButtonItem *rightBarButtonItem
  

Следовательно, вызов self.navigationItem.rightBarButtonItem сохранит 1 для передаваемого вами объекта, а затем вы выделяете / инициализируете, что является еще одним сохранением 1. UINavigationItem Освободит его сохранение, когда оно будет освобождено, но ваше исходное сохранение все еще будет висеть поблизости.

Исправление:

 UIBarButtonItem *rightBarButtonItem = [[UIBarButtonItem alloc] initWithCustomView:self.tools];
self.navigationItem.rightBarButtonItem = rightBarButtonItem;
[rightBarButtonItem release]; rightBarButtonItem = nil;
  

Комментарии:

1. Я все еще получаю предупреждение, вызванное этой строкой self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithCustomView:self.tools];

Ответ №2:

 self.pickerSortingDataCurrent = [[NSArray alloc] initWithObjects:
  @"Next Date Ascending", 
  @"Next Date Descending", nil];     // removed some items here
  

1 сохранить количество для alloc, 1 сохранить количество для присвоения retain @property .

Перепишите это как:

 NSArray *labels = [[NSArray alloc] initWithObjects:
  @"Next Date Ascending", 
  @"Next Date Descending", nil];
self.pickerSortingDataCurrent = labels;
[labels release];
  

(Или вы могли бы использовать autorelease )

Комментарии:

1. Это все еще выдает мне предупреждение из строки перед см. Комментарий выше.

Ответ №3:

Если вы создаете свойство с помощью retain , вы должны установить для него значение nil в вашем методе dealloc.

т. е.

 @interface DMFakeyClass : NSObject

@property (nonatomic, retain) NSString *bogusString;

@end

@implementation DMFakeyClass

-(void)dealloc {
    self.bogusString = nil;
    [super dealloc];
}

@end
  

Это практически все, что вам нужно сделать, чтобы иметь успешную стратегию управления памятью. При использовании этого свойства всегда используйте средство получения / установки ( self.bogusString = [NSString stringWithString:@"bogus"]; ) и убедитесь, что вы автоматически выпустили все, что выделили ( self.bogusString = [[[NSString alloc] initWithString:@"bogus2"] autorelease]; ). Следуйте этому шаблону, и у вас не должно возникнуть никаких проблем.