直到昨天我才认为我已经理解了iPhone的内存管理。 那么这是我的问题:
// .h file
@property(nonatomic, retain) NSMutableDictionary *dicParams;
@property(nonatomic, retain) NSMutableDictionary *dicReferences;
@property(nonatomic, retain) FtMonitorHandler *monitorHandler;
// .m file
@synthesize dicParams, dicReferences, monitorHandler;
- (id)init {
self = [super init];
if (self) {
self.dicParams = [[NSMutableDictionary alloc] init];
self.dicReferences = [[NSMutableDictionary alloc] init];
self.monitorHandler = [[FtMonitorHandlerService alloc] init];
}
return self;
}
- (void)dealloc {
[monitorHandler release];
[dicParams release];
[dicReferences release];
[super dealloc];
}
如果我在其他地方设置了,例如在viewcontroller的分配之后
self.dicParams = dicValues;
......它会变成泄密
我对使用“self。...”设置实例变量的理解是,当前值将被“释放”,然后设置为“retain”。
我尝试了一些乐器。结果:
-(void)createLeak {
self.dicParams = [[NSMutableDictionary alloc] init];
self.dicParams = [[NSMutableDictionary alloc] init];
}
-(void)createAnotherLeak {
self.dicParams = [[NSMutableDictionary alloc] init];
self.dicParams = nil;
self.dicParams = [[NSMutableDictionary alloc] init];
}
- (void)createWithoutLeak {
if(dicParams != nil) [dicParams release];
self.dicParams = [[NSMutableDictionary alloc] init];
}
我是否遗漏了某些内容,或者这是否应该是这样的行为?
编辑:我尝试实施建议的更改。它工作正常,因为我的变量不是GUI元素。 (UIView,UILabel等)
自动释放将导致内存警告后应用程序崩溃
- (void)loadView {
[super loadView];
// ... here is some other stuff ...
self.lblDeparture = [[[UILabel alloc] init] autorelease];
}
- (void)viewDidUnload {
[super viewDidUnload];
// Release any retained subviews of the main view.
self.lblDeparture = nil;
}
- (void)dealloc {
[lblDeparture release];
[super dealloc];
}
我不太确定,但我认为以下几行是真正的问题:
CGRect frame = CGRectMake(0, 0, self.view.frame.size.width, INFO_VIEW_HEIGHT);
UIImageView *imageView = [[UIImageView alloc] initWithFrame:frame];
[imageView addSubview:lblDeparture];
[lblDeparture release]; // is this correct?
[self.view addSubview:imageView];
[imageView release];
答案 0 :(得分:4)
如果您是初始化,则需要自动释放。
-(void)dontCreateAnotherLeak {
self.dicParams = [[[NSMutableDictionary alloc] init] autorelease];
self.dicParams = nil;
self.dicParams = [[[NSMutableDictionary alloc] init] autorelease];
}
更容易的是使用便利存取器。
self.dicParams = [NSMutableDictionary dictionary];
如果你想自己处理这个问题。在@synthesize dictParams之上;你也想创建自己的二传手。
-(void)setDictParams:(NSMutableDictionary*) newDictParams
{
if (dictParams != newDictParams)
{
[dictParams release];
dictParams = [newDictParams retain];
}
}
这有点简单。但基本上是编译器使用添加到@property标记的保留修饰符创建的内容
答案 1 :(得分:0)
如果您在retain
中设置了一个已指定property
的实例变量,则保留计数变为1
现在,当您调用self时,因为“self.variable = value”将retain
计数增加1,因此总保留计数变为2.
现在要释放它,你需要将保留计数设置为0.因此你需要释放它两次。
希望这有帮助。
答案 2 :(得分:0)
我不确定我完全理解这个问题,但你的第二部分很容易解释......
- (void)createLeak {
self.dicParams = [[NSMutableDictionary alloc] init]; self.dicParams = [[NSMutableDictionary alloc] init];
很明显......
现在但是这个
- (void)createAnotherLeak {
self.dicParams = [[NSMutableDictionary alloc] init]; self.dicParams = nil; self.dicParams = [[NSMutableDictionary alloc] init]; }
不释放第一个分配的self.dicParams,而是通过将其设置为nil然后使用新的重置它来忘记对它的任何引用。设置为nil不等于release。如果您已经使用autorelease创建了第一个,然后将其设置为nil则会有所不同。这应该正常工作。你用你的第三个例子做了很多事情!
现在关于你的初始问题,当你写
时泄漏的是什么self.dicParams = dicValues;
变量self.dicParams应该保留该值,直到您再次释放它为止
答案 3 :(得分:0)
我建议您仔细阅读Apple的内存管理编程指南。 http://developer.apple.com/library/ios/#documentation/Cocoa/Conceptual/MemoryMgmt/MemoryMgmt.html
这一切都在那里解释。
我可以看到你犯的一些明显的错误。
首先,您不应在init
或dealloc
中使用访问者。
所以,这个
- (id)init {
self = [super init];
if (self) {
self.dicParams = [[NSMutableDictionary alloc] init];
self.dicReferences = [[NSMutableDictionary alloc] init];
self.monitorHandler = [[FtMonitorHandlerService alloc] init];
}
return self;
}
应该是
- (id)init {
self = [super init];
if (self) {
dicParams = [[NSMutableDictionary alloc] init];
dicReferences = [[NSMutableDictionary alloc] init];
monitorHandler = [[FtMonitorHandlerService alloc] init];
}
return self;
}
其次,当你设置一个保留属性时,你需要释放你设置它的任何东西。
所以,这个
self.dicParams = [[NSMutableDictionary alloc] init];
应该是
self.dicParams = [[[NSMutableDictionary alloc] init] autorelease];
或者你可以这样做
NSMutableDictionary *newDicParams = [[NSMutableDictionary alloc] init];
self.dicParams = newDicParams;
[newDictParams release];
答案 4 :(得分:0)
@synthesize
为(readwrite, retain, nonatomic)
属性生成的setter看起来像这样:
- (void) setSomething: (id) newSomething;
{
if (something != newSomething) {
[something release];
something = [newSomething retain];
}
}
实例变量something
指向的旧对象将被释放,而新对象将被保留。
你的错误是创造对象。您使用[[NSDictionary alloc] init]
创建字典。此字典的保留计数为1.您的setter保留对象,因此新的保留计数为2.当您再次调用setter时,原始字典的保留计数会正确地减少 - 它再次为1。要释放字典,您必须再次释放它。为此,有autorelease
。一段时间后,自动释放的对象将被释放。因此,设置属性的正确代码将是
self.something = [[[NSDictionary alloc] init] autorelease];
甚至更好地使用便利分配器
self.something = [NSDictionary dictionary];
你真的应该阅读并理解Apple的内存管理指南 - 这一切都在那里解释。
顺便说一下,我在这里讨论了保留计数。考虑它们是可以的,但是你永远不应该向对象询问它的保留计数,这个值是无用的,因为它很少你想到的。