我是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”是一个潜在的泄漏。我试图在最后释放它或使用自动释放但是都不能正常工作。每次我调用方法我的应用程序都会终止。非常感谢你!
答案 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;这非常有帮助。