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

7

我是新手,涉及到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;
}

分析器告诉我我的“结果”可能会出现泄漏(leak)。但是我应该在哪里释放它呢?

在@property中,何时使用assign、copy、retain等有什么简单的记忆规则吗?

另一个问题:

- (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”是一个潜在的泄漏。我尝试在最后释放它或使用autorelease,但都无法正常工作。每次调用该方法时,我的应用程序都会终止。再次感谢您!

3个回答

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控制器,例如在应用程序委托的实例变量中。

非常感谢。您是否也知道@property问题的规则? - n3on
如果一个属性被声明为retaincopy,那么你应该在类的dealloc方法中释放它的实例变量。 - BoltClock
@BoltClock:好的,谢谢。但是什么时候应该使用copy、retain或assign? - n3on
@n3on:Sherm Pendley的回答可能会有所帮助。 - BoltClock
@BoltClock: 我又有一个问题,如果您能帮助我就太好了。我编辑了我的首帖。 - n3on
@n3on:看看将其保留在你的类中是否有帮助。 - BoltClock

3
BoltClock的回答对于你问题的第一部分非常准确。我来试着解决剩下的部分。
Assign用于简单的非对象类型,例如int、double或struct。它生成一个setter,执行普通的赋值操作,如“foo = newFoo”。Copy&retain会根据它们的名称,复制新值(“foo = [newFoo copy]”)或保留它(“foo = [newFoo retain]”)。在这两种情况下,setter会适当地释放旧值。
那么问题是,什么时候需要复制,什么时候需要保留。答案是...这取决于情况。你的类如何使用新值?如果其他代码修改传入的对象,你的类会出现问题吗?例如,你有一个NSString*属性,名为“theString”。其他代码可以将NSMutableString实例分配给theString——这是合法的,因为它是一个NSString子类。但是,那个其他代码可能也会保留其自己的引用到可变字符串对象,并改变它的值——你的代码能处理这种可能性吗?如果不能,它应该制作自己的副本,而其他代码无法更改。
另一方面,如果你自己的代码不假设theString可能已经被更改,并且无论它是否更改都可以正常工作,那么保留传入对象而不必要地制作副本会节省内存。
基本上,规则(有时不那么简单)是仔细考虑你的代码是否需要自己的私有副本,或者能够正确处理共享对象,其值可能被其他代码更改。

有时候你需要在对象类型上使用赋值操作符,这不仅仅适用于非对象类型。 - GendoIkari
保留循环引用、委托和连接的IBOutlets等内容。我试图保持简单,但可能过于简化了。 - Sherm Pendley
我一直保留IBOutlets...它们应该被分配的原因是什么?除了您自己的控制器类之外,它们是否被其他任何东西保留? - GendoIkari
我在考虑模拟旧的行为,即如果没有setter方法,IBOutlet ivar将被简单地分配。老狗也能学会新把戏,但有时我们很难忘记旧的习惯... - Sherm Pendley

1
在将对象添加到gastroCategoryList数组中时,您可以释放gc的原因是当一个对象被添加到数组中时,该数组会保留该对象。因此,即使释放了gc,它仍然存在于gastroCategoryList中,被其保留着。
当您从方法返回一个新创建的对象时,需要调用autorelease。这将导致对象仅在运行时离开调用方法的范围后才被释放,从而使调用方法有机会对返回的值进行操作。
请注意,如果您的方法以单词copy或new开头,则不应该自动释放对象;应该将其留给调用方法来释放。
至于复制vs保留vs分配……作为一般规则,应复制具有可变版本的对象,例如NSArray、NSSet、NSDictionary和NSString。这将确保您所指向的对象在您不想要它时不可变。
否则,每当您希望确保对象仍然在内存中时,请使用retain。这适用于几乎所有对象,除了被视为您对象父级的对象,此时您将使用assign。(请参见关于保留循环的部分here)。
还要注意,对于诸如int之类的非对象类型,必须使用assign。
阅读一下内存Management Programming Guide指南;它非常有帮助。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接