iPhone - NSMutableArray внутри пользовательского объекта.Когда выпустить? - PullRequest
1 голос
/ 02 февраля 2011

Когда я должен выпустить [self.activeLocations], что является NSMutableArray внутри моего пользовательского объекта?Я также получаю утечки памяти в initWithValue.

Также объект Location ниже.Я вызываю это и освобождаю это правильно?

Метод в Custom Object.m:

- (id)initWithValue:(NSString *)value {
    if ((self = [super init])) {
        self.couponId = [value valueForKey:@"couponId"];
        self.couponName = [value valueForKeyPath:@"couponName"];
        self.qrCode = [value valueForKeyPath:@"description"];
        self.companyName = [value valueForKeyPath:@"companyName"];
        self.categoryName = [value valueForKeyPath:@"categoryName"];
        self.distance = [value valueForKeyPath:@"distance"];

        NSDictionary *activeLocationsDict = [value valueForKeyPath:@"activeLocations"];
        //self.activeLocations = [[[NSMutableArray alloc] init] autorelease];
        self.activeLocations = [NSMutableArray array];
        for (id val in activeLocationsDict) {
            // Add JSON objects to array.
            Location *l = [[Location alloc] initWithValue:val];
            [self.activeLocations addObject:l];
            [l release];
        }
    }

    return self;
}

- (void)dealloc {
    [super dealloc];
    couponId = nil;
    couponName = nil;
    qrCode = nil;
    companyName = nil;
    categoryName = nil;
    distance = nil;
    activeLocations = nil;
}

Мой Custom Object.h

@interface Coupon : NSObject {
    NSNumber *couponId;
    NSString *couponName;
    NSString *qrCode;
    NSString *companyName;
    NSString *categoryName;
    NSString *distance;
    NSMutableArray *activeLocations;
}

@property (nonatomic, copy) NSNumber *couponId;
@property (nonatomic, copy) NSString *couponName;
@property (nonatomic, copy) NSString *qrCode;
@property (nonatomic, copy) NSString *companyName;
@property (nonatomic, copy) NSString *categoryName;
@property (nonatomic, copy) NSString *distance;
@property (nonatomic, retain) NSMutableArray *activeLocations;

- (id)initWithValue:(NSString *)value;

Вот как ям, используя выше initWithValue:

- (NSMutableArray *)createArrayOfCoupons:(NSString *)value {
    NSDictionary *responseJSON = [value JSONValue];

    // Loop through key value pairs in JSON response.
    //NSMutableArray *couponsArray = [[NSMutableArray alloc] init] autorelease];
    NSMutableArray *couponsArray = [NSMutableArray array];

    for (id val in responseJSON) {
        // Add JSON objects to array.
        Coupon *c = [[Coupon alloc] initWithValue:val];
        [couponsArray addObject:c];
        [c release];
    }

    return couponsArray;
}

Я получаю утечки памяти на initWithValue и в вышеуказанном методе ...

enter image description here

Location Пользовательский объект:

- (id)initWithValue:(NSString *)value {
    if ((self = [super init])) {
        self.locationId = [value valueForKeyPath:@"locationId"];
        self.companyName = [value valueForKeyPath:@"companyName"];
        self.street1 = [value valueForKeyPath:@"street1"];
        self.street2 = [value valueForKeyPath:@"street2"];
        self.suburb = [value valueForKeyPath:@"suburb"];
        self.state = [value valueForKeyPath:@"state"];
        self.postcode = [value valueForKeyPath:@"postcode"];
        self.phoneNo = [value valueForKeyPath:@"phoneNo"];
        self.latitude = [value valueForKeyPath:@"latitude"];
        self.longitude = [value valueForKeyPath:@"longitude"];
    }

    return self;
}

- (void)dealloc {
    [super dealloc];
    locationId = nil;
    companyName = nil;
    street1 = nil;
    street2 = nil;
    suburb = nil;
    state = nil;
    postcode = nil;
    phoneNo = nil;
    latitude = nil;
    longitude = nil;
}

Ответы [ 4 ]

2 голосов
/ 02 февраля 2011
- (id)init {
   ....
}

Избавьтесь от этого.Это ничего не делает.

- (id)initWithValue:(NSString *)value {
    [super init];

Существует определенный шаблон, который вы должны использовать для инициализации:

- (id)initWithValue:(NSString *)value {
    if (( self = [super init] )) {
      // everything except the return
    }
    return self;
}

Наконец, чтобы ответить на ваш реальный вопрос, предполагая, что вы используете retain с вашимсвойство, есть два места, которые вам нужно освободить.

Вот первое:

self.activeLocations = [[NSMutableArray alloc] init];

Почему : [[NSMutableArray alloc] init] делает ваш код владельцем объекта, сохраняяЭто.Но набор собственности также требует собственности, сохраняя это.Вы действительно не хотите, чтобы этот NSMutableArray принадлежал коду и для вашего пользовательского объекта, вы хотите, чтобы он принадлежал вашему объекту.

Я предлагаю просто использовать это:

self.activeLocations = [NSMutableArray array];

Второе место в вашей раздаче:

- (void)dealloc {
    self.activeLocations = nil;

    // ...and everything else you've set as a property using retain

    [super dealloc];
}

(Лично я ходил взад-вперёд относительно использования точечной нотации в dealloc вместо [activeLocations release];. Япредпочитая установку на ноль, используя свойство сейчас, которое помещает все правила управления памятью в одно место.)

У Apple есть отличный документ по управлению памятью, который вы должны прочитать: Руководство по программированию управления памятью: Владение объектамии утилизация .

2 голосов
/ 02 февраля 2011

Прежде всего, ваш переопределенный метод -init является совершенно ненужным , поскольку по умолчанию при вызове метода среда выполнения будет выполнять восходящий обход иерархии наследования до тех пор, пока не будет найден указанный метод, поэтомуон найдет метод NSObject -init и вызовет его.

Во-вторых, вы должны вызвать release для всех ваших собственных свойств (свойства с copy или retain) в переопределенных-dealloc method.

В-третьих, в вашем случае, когда вы вызываете установщик свойства, передавая объект, который уже принадлежит локально, вы должны отправить объекту сообщение release после вызова установщика для правильной передачи.от владения объектом до получателя.

Есть два способа сделать это:

Один из способов - создать принадлежащий вам объект, используя alloc, copy или * 1021.*, а затем вызовите установщик свойства, передав этот объект, а затем отправьте ему сообщение release.

Другой способ - передать автоматически освобожденный объект в установщик свойства,который затем будет retain или copy своим аргументом и тем самым получит право собственности

1 голос
/ 02 февраля 2011

Ответ на когда вы должны выпустить, это вопрос того, являются ли массив activeLocations и все элементы в этом массиве (помните, что каждый элемент в массиве сохраняется самим массивом)необходимо в течение всего времени существования объекта Location.

Если вы используете массив activeLocations для каких-то временных целей, например, в методе или цепочке методов, то он вам больше не нужен, или вы планируете обновить егочлены в более позднее время, когда вам понадобится следующий, тогда имеет смысл освобождать массив (и его элементы, который является автоматическим), когда вы закончите использовать его, в любой функции, которая в последний раз использует массив.Вы будете использовать соглашение

self.activeLocations = nil;

, чтобы позволить исполняющей системе освободить массив и установить член равным nil.

Если, с другой стороны, activeLocationsданные массива являются обязательными для функционирования объекта Locations и должны существовать, пока существует объект Location, тогда вы захотите освободить массив внутри метода dealloc объекта Location, например:

- (void) dealloc {
    [activeLocations release];

    [super dealloc];
}

Как это случается, вы почти всегда захотите освободить объекты-члены, такие как activeLocations, в методе dealloc.Это гарантирует, что при освобождении объекта Location очищенные элементы, которые он содержит, очищаются.Помните, что Objective-C не вызывает методы для нулевых указателей, поэтому, если вы ранее установили activeLocations равным нулю, вызов в dealloc является безопасным запретом.

Учитывая то, что вы всегда настроитевыпуск в dealloc, теперь вам действительно нужно спросить себя, нужна ли вам фаза освобождения / воссоздания где-то в жизненном цикле вашего объекта (опять же, определяется требованиями частоты использования).

0 голосов
/ 02 февраля 2011

Это зависит от того, что вы спрашиваете. В initWithValue: метод, которым вы поделились, вы дважды сохраняете массив. Он должен быть освобожден или автоматически выпущен один раз в initWithValue:.

Массив должен быть освобожден во второй раз с помощью метода dealloc пользовательского объекта.

...