繁体   English   中英

iPhone-自定义对象内的NSMutableArray。 什么时候发布?

[英]iPhone - NSMutableArray inside a Custom Object. When to release?

什么时候应该释放[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;
}

我的自定义对象

@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上发生内存泄漏...

在此处输入图片说明

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

首先, 完全不需要覆盖的-init方法,因为默认情况下,调用方法时,运行时将对继承层次结构进行向上遍历,直到找到指定的方法为止,因此它将找到NSObject-init方法,并调用它。

其次,你应该调用release所有你拥有的财产(那些与copyretain在你重写) -dealloc方法。

第三,在您的情况下,当您调用属性设置器以传递已在本地拥有的对象时,必须在调用设置器以将对象的所有权正确移交给接收方之后向该对象发送release消息。

有两种方法可以做到这一点:

一种方法是使用alloccopynew创建您拥有的对象,然后调用属性设置器,传入该对象,然后向其发送release消息。

另一种方法是将自动释放的对象传递给属性设置器,该属性设置器将retaincopy其参数,从而获得所有权

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

第二个位置是您的dealloc:

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

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

    [super dealloc];
}

(就个人而言,我反复讨论了是否在dealloc中使用点符号,而不是[activeLocations release];我现在喜欢使用属性设置为nil,这将所有内存管理规则放在一个位置。 )

Apple有一份有关内存管理的出色文档,您应该阅读: 内存管理编程指南:对象所有权和处置

何时释放它的答案是一个问题,即在Location对象的整个生命周期中是否都需要activeLocations数组和该数组中的所有元素(记住数组中的每个元素都由数组本身保留)。

如果将activeLocations数组用于某个临时目的(例如,在一个方法或方法链中),则不再需要它,或者计划在以后需要它的时候刷新它的成员,那么这很有意义在使用完该数组(及其最后使用该数组的任何函数)后释放该数组(及其元素,这是自动的)。 您将使用约定

self.activeLocations = nil;

让运行时系统释放数组并将成员设置为nil。

另一方面,如果activeLocations数组数据是Locations对象运行所必需的,并且只要Location对象存在就必须存在,那么您将需要在Location对象的dealloc方法内释放该数组,例如:

- (void) dealloc {
    [activeLocations release];

    [super dealloc];
}

碰巧的是,您几乎总是要在dealloc方法中释放成员对象,例如activeLocations。 这样可以确保在释放Location对象时,将清除其中包含的成员。 请记住,Objective-C不会在空指针上调用方法,因此,如果您先前已将activeLocations设置为nil,则在dealloc中的调用是安全的禁止操作。

既然如此,您将始终设置要在dealloc中释放的内容,那么现在您只需要问自己是否需要在对象生命周期中某个位置进行释放/重新创建阶段(同样,由使用频率要求决定)。

这取决于您的要求。 在您共享的initWithValue:方法中,您要双重保留数组。 应该在initWithValue:中释放或自动释放一次。

该数组应该在自定义对象的dealloc方法中再次释放。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM