如何在for循环中释放对象?

时间:2011-03-23 19:02:13

标签: iphone objective-c ios ipad memory-management

我是cocoa / objective-c的新手,而且我正在使用我的对象的版本。我有以下代码:

gastroCategoryList = [[NSMutableArray alloc] init];
for (NSDictionary *gastrocategory in gastrocategories) {
    NSString *oid = [gastrocategory objectForKey:@"id"];
    GastroCategory *gc = [[GastroCategory alloc] initWithId:[oid intValue] name:[gastrocategory objectForKey:@"name"]];
    [gastroCategoryList addObject:gc];
}

分析仪向我显示for中定义的“gastrocategory”是潜在的内存泄漏。但我不确定我是否可以在for循环结束时释放它?

同样在以下代码中:

- (NSArray *)eventsForStage:(int)stageId {

    NSMutableArray *result = [[NSMutableArray alloc] init];

    for (Event *e in eventList) {
        if ([e stageId] == stageId) {
            [result addObject:e];
        }
    }

    return result;
}

分析仪告诉我,我的“结果”是潜在的泄漏。但是我应该在哪里发布这个?

当我应该在@property使用分配,复制,保留等时,是否还有一个简单的记忆规则?

另一个问题:

- (IBAction)showHungryView:(id)sender {
    GastroCategoriesView *gastroCategoriesView = [[GastroCategoriesView alloc] initWithNibName:@"GastroCategoriesView" bundle:nil];

    [gastroCategoriesView setDataManager:dataManager];

    UIView *currentView = [self view];
    UIView *window = [currentView superview];

    UIView *gastroView = [gastroCategoriesView view];

    [window addSubview:gastroView];

    CGRect pageFrame = currentView.frame;
    CGFloat pageWidth = pageFrame.size.width;
    gastroView.frame = CGRectOffset(pageFrame,pageWidth,0);

    [UIView beginAnimations:nil context:NULL];
    currentView.frame = CGRectOffset(pageFrame,-pageWidth,0);
    gastroView.frame = pageFrame;
    [UIView commitAnimations];

    //[gastroCategoriesView release];
}

我不明白,“gastroCategoriesView”是一个潜在的泄漏。我试图在最后释放它或使用自动释放但是都不能正常工作。每次我调用方法我的应用程序都会终止。非常感谢你!

3 个答案:

答案 0 :(得分:9)

在循环中,将每个gc添加到列表后释放,因为您不再需要它在循环范围中:

gastroCategoryList = [[NSMutableArray alloc] init];
for (NSDictionary *gastrocategory in gastrocategories) {
    NSString *oid = [gastrocategory objectForKey:@"id"];
    GastroCategory *gc = [[GastroCategory alloc] initWithId:[oid intValue] name:[gastrocategory objectForKey:@"name"]];
    [gastroCategoryList addObject:gc];
    [gc release];
}

在您的方法中,声明result是自动释放的,以便从您的方法中解除对其的所有权:

NSMutableArray *result = [[[NSMutableArray alloc] init] autorelease];

// An alternative to the above, produces an empty autoreleased array
NSMutableArray *result = [NSMutableArray array];
第三期中的

编辑:,您无法释放视图控制器,因为窗口正在使用其视图。将其设置为自动释放也会导致相同的命运,只会延迟。

您必须在某处保留GastroCategoriesView控制器,例如在您的app delegate的实例变量中。

答案 1 :(得分:3)

对于问题的第一部分,BoltClock的回答是正确的。我会尝试解决剩下的问题。

Assign用于简单的非对象类型,例如int,double或struct。它生成一个执行普通旧赋值的setter,如“foo = newFoo”。复制&保留将,正如他们的名字所暗示的,要么复制新值(“foo = [newFoo copy]”)或保留它(“foo = [newFoo retain]”)。在这两种情况下,setter都会根据需要释放旧值。

所以问题是,何时复制以及何时保留。答案是......这取决于。你的班级如何使用新值?如果其他一些代码修改了传入的对象,你的类会破坏吗?比方说,你有一个富有想象力地命名为“theString”的NSString *属性。其他代码可以将一个NSMutableString实例分配给theString - 这是合法的,因为它是一个NSString子类。但是其他代码也可能保留自己对可变字符串对象的引用,并更改其值 - 您的代码是否准备好处理这种可能性?如果没有,它应该自己制作副本,其他代码不能改变。

另一方面,如果你自己的代码没有假设theString是否可能已被更改,并且无论是否有效,那么你将通过保留传入的对象来节省内存,而不是不必要的它的副本。

基本上,规则(遗憾的是,有时候并不那么简单)是仔细考虑自己的代码是否需要自己的私有副本,或者能够正确处理其值可能被其他代码更改的共享对象。

答案 2 :(得分:1)

将gc添加到gastroCategoryList后可以释放gc的原因是当一个对象被添加到数组时,该数组会保留该对象。所以,即使你释放你的gc,它仍然会存在;由gastroCategoryList保留。

当你从一个方法返回一个新创建的对象时,你需要调用autorelease.这将导致只有在运行时离开调用方法的范围后才释放该对象,从而给出调用方法用返回值做某事的机会。

请注意,如果您的方法以单词copy或new开头,那么您应该自动释放您的对象;你应该把它留给调用方法来释放。

至于copy vs retain vs assign ...作为一般规则,复制具有可变版本的对象,例如NSArray,NSSet,NSDictionary和NSString。这将确保您有指针的对象在您不希望它时是不可变的。

否则,只要您希望确保某个对象仍在内存中,就可以使用retain。这将适用于几乎所有对象,除了被视为对象父对象的对象,在这种情况下,您将使用assign。 (参见保留周期here部分)。

另请注意,必须为非对象类型(例如int。

)使用assign

稍微阅读内存Management Programming Guide;这非常有帮助。