Как у меня течет память?

У меня есть табличное представление, что при загрузке создает объект лица

Person.h

#import <UIKit/UIKit.h>
#import "TwitterHelper.h"

@interface Person : NSObject {
    NSDictionary *userInfo;
    NSURL *image;
    NSString *userName;
    NSString *displayName;
    NSArray *updates;
}
/*
@property (retain) NSString *userName;
@property (retain) NSString *displayName;
@property (retain) NSDictionary *userInfo;
 */
@property (nonatomic, copy) NSURL *image;
@property (retain) NSArray *updates;

- (id)initWithUserName:userName;

@end

Person.m

#import "Person.h"


@implementation Person

/*
@synthesize userName;
@synthesize displayName;
@synthesize userInfo;
 */
@synthesize image;
@synthesize updates;

- (id)initWithUserName:(NSString *)user{

    userName = user;
    userInfo = [TwitterHelper fetchInfoForUsername:user];
    displayName = [userInfo valueForKey:@"name"];
    image = [NSURL URLWithString:[userInfo valueForKey:@"profile_image_url"]];
    updates = [TwitterHelper fetchTimelineForUsername:userName];

    return self;
}

- (void)dealloc
{
    /*
    [userName release];
    [displayName release];
    [updates release];
     [userInfo release];
     [image release];
     */
    [super dealloc];
}

@end

Внутри моего метода UITableView cellAtRowForIndexPath я создаю каждый объект person и присваиваю свойство изображения примерно так...

Person *person = [[Person alloc] initWithUserName:userName];

NSData *data = [[NSData alloc] initWithContentsOfURL:person.image];
[data release];

Когда я запускаю это в Instruments, оно выделяет строку NSData *data..., говорящую о том, в чем именно утечка.

Почему там течет?

3 ответа

Во-первых, вам нужно понять разницу между переменными экземпляра и свойствами и методами получения / установки.

  • Переменные экземпляра (ivars) - это переменные, хранящиеся в вашем объекте. Вы получаете доступ к ivar из метода, просто называя его (например, "userName").
  • Свойства определяют интерфейс для вашего объекта, позволяя считывать и / или записывать информацию в ваш объект.
  • getters / setters реализуют этот интерфейс и могут использовать ivar в качестве резервного хранилища

Вы получаете доступ к свойству с помощью метода получения / установки, либо явно (например, [self userName]), либо (эквивалентно), используя точечный синтаксис self.userName. Обратите внимание, что эти две записи абсолютно идентичны. Вы объявляете свойство (т.е. вы объявляете интерфейс для вашего объекта), используя @property в интерфейсе вашего объекта, что-то вроде:

@property (copy) NSString* userName;

Это заявление по существу эквивалентно печатанию:

- (NSString*) userName;
- (void) setUserName: (NSString*) theUserName;

Вы реализуете свойство, либо используя @synthesize (который просто говорит компилятору написать для вас getter / setter), либо реализуя его самостоятельно (т.е. вы пишете реализацию методов для userName и setUserName). Существует также редко используемая третья опция, @dynamic, которая сообщает компилятору, что вы будете обрабатывать методы во время выполнения, по сути просто отправляя предупреждение, которое вы в противном случае получили бы.

Далее вам необходимо прочитать и понять правила управления памятью. Это только 9 коротких параграфов, иди, прочти это сейчас, я буду ждать. Готово? хорошо.

Кроме того, вам нужно знать, что вы не должны использовать методы получения / установки в процедурах init или dealloc.

Итак, ваша процедура инициализации должна выглядеть примерно так:

- (id)initWithUserName:(NSString *)user{
    userName = [user copy];
    userInfo = [[TwitterHelper fetchInfoForUsername:user] retain];
    displayName = [[userInfo valueForKey:@"name"] copy];
    image = [[NSURL URLWithString:[userInfo valueForKey:@"profile_image_url"]] copy];
    updates = [[TwitterHelper fetchTimelineForUsername:userName] retain];
    return self;
}

Обратите внимание, что вы вступаете во владение каждым значением, которое храните в ivar с сохранением или копированием. Как правило, вы используете copy для NSString для преобразования NSMutableStrings в ваши собственные NSStrings, а не для сохранения, в результате чего у вас будет ссылка на возможно изменяемую строку. Та же проблема относится к NSArray/NSDictionary, но мы будем предполагать, что TwitterHelper намеревается передать извлеченные данные.

Ваш диллок должен будет выпустить различные ивары:

- (void)dealloc
{
    [userName release];
    [displayName release];
    [updates release];
    [userInfo release];
    [image release];
    [super dealloc];
}

В любом другом месте вашего кода вы будете использовать self.userName для доступа или изменения свойств, а не для прямого доступа к ivars.

Обратите внимание, что вы можете вообще не хранить displayName (и аналогичное изображение), а просто реализовать средство получения свойства, которое извлекает его из userInfo. Для этого удалите displayName ivar, измените свойство на:

@property (только для чтения) NSString *displayName;

удалите @synthesize displayName и добавьте получатель вручную:

- (NSString*) displayName
{
    return [userInfo valueForKey:@"name"];
}

и удалите релиз в dealloc.

Обратите внимание, что вам не нужно сохранять / освобождать значение в displayName - вы возвращаете значение, которое не принадлежит получателю, и вы сами можете скопировать / сохранить его, если они захотят сохранить его.

Если вы решили создать свойство, вы должны использовать:

self.image = [NSURL URLWithString:[userInfo valueForKey:@"profile_image_url"]];

в вашем init сообщение а не

image = [NSURL URLWithString:[userInfo valueForKey:@"profile_image_url"]];

Установка значения без self префикс не будет вызывать copy или же retain сообщение, и создаст проблему с памятью (не обязательно утечка).

Это может быть тем, на что указывают инструменты.

(Это очевидно относится ко всем свойствам!)

Кроме того, если вы не хотите использовать аксессор, то retain или же copy полученное значение, например:

image = [[NSURL URLWithString:[userInfo valueForKey:@"profile_image_url"]] retain];

Ты звонишь alloc на человека, но не выпуская его. Вы слили свой person объект. (в конфигурации вашей ячейки)

Другие вопросы по тегам