更具体的通用 Objective-C 内存管理
Posted
技术标签:
【中文标题】更具体的通用 Objective-C 内存管理【英文标题】:More Specific, General Objective-C Memory Management 【发布时间】:2009-10-22 22:29:11 【问题描述】:我读过的所有关于objective-c 内存管理的内容都让人难以置信地简单。用每个人的话说:“释放你分配、保留或复制的任何东西”。但我认为还有一些更具体的情况不是那么明确。以下是一些示例情况。每个的正确程序是什么:
情况#1:
Foo *foo = [[foo alloc] init];
Foo *fooToo = [[[foo alloc] init] autorelease];
foo = fooToo;
foo在分配给fooToo之前需要释放吗?
情况#2 当我执行以下操作时,我似乎遇到了很多崩溃: (为方便起见,.h 和 .m 混合在一起)
Foo *foo;
@property (nonatomic, retain) Foo *foo;
@synthesize foo;
-(id)init
self = [super init];
-(void)dealloc
[super dealloc];
[foo release];
我经常被告知“总是在 dealloc 中释放你设置保留属性的内容”。但如果像我展示的那样完成,这将崩溃。
情况#3 类似的情况也会崩溃: (为方便起见,.h 和 .m 混合在一起)
Foo *foo;
@property (nonatomic, retain) Foo *foo;
@synthesize foo;
-(id)init
self = [super init];
self.foo = nil;
-(void)dealloc
[super dealloc];
[foo release];
由于某种原因,当我的代码变为 dealloc 时,foo 不是 == nil。
情况 #4 最后,只是一个问题,人们在做出决定时使用的一般思维过程是什么
self.foo = bar;
和
foo = bar;
何时声明 foo 与上述情况相同? self.foo
只是另一种编码方式吗:
foo = [bar retain]
;
【问题讨论】:
与问题无关,但您应该阅读有关 Cocoa 初始化程序的信息。这是一个很好的讨论:mikeash.com/?page=pyblog/… 【参考方案1】:情况#1:
是的,您确实需要在失去对它的引用之前释放foo
。鉴于您分配了它,您有责任释放它。如果在释放之前重新分配foo
,就不能再释放了!
情况#2:
dealloc
的正确实现是:
- (void)dealloc
[foo release];
[super dealloc];
dealloc
方法需要调用super 的dealloc
方法而不是release
方法。另外,在调用[super dealloc]
之前需要先释放字段
情况 #3: 与情况 #2 相同。
情况#4:
我总是更喜欢使用self.foo = bar
,因为如果需要,它会自动执行以下步骤:
-
释放
foo
保留bar
将foo
分配给bar
分配foo = bar
和foo = [bar retain]
不会释放foo
的前一个对象。
【讨论】:
有趣!对于刚刚开始使用 Objective-C 的人来说,这是一个很好的信息。 (我)self.foo = bar
与发送 [self setFoo:bar]
完全相同(除非选择了不同的设置器)。
self.foo = bar 也会发送 KVO 通知。 foo = bar 不会。
如果你实现了自己的 -setFoo: 方法,那么 self.foo = bar 将调用你实现的方法。【参考方案2】:
等等。停止。 Msaeed 逐行回答是正确的,但没有强调真正的问题。
您要么没有像计算机一样思考,要么您对每行代码的太多魔力进行了假设。
请不要把它当作一种侮辱——这是一个非常容易犯的错误,几乎每个程序员在刚接触环境时都会犯这个错误(我在开始使用 Objective-C 时做了一些非常神奇的假设1989)。
让我们重新考虑一下情况。
情况#1: ...删除不相关的代码...
foo = fooToo;
这是一个简单的任务。在此之前包含的任何foo
(在您的情况下是对对象的引用)现在都将被fooToo
的值覆盖。没有魔法。不涉及额外的方法执行或代码行。
如果foo
包含对该代码行之前的保留对象的引用。引用将被覆盖。如果您需要在覆盖引用之前release
foo
,请这样做,但这与分配正交。
情况 #2: ...删除不相关的代码...
-(void)dealloc
[super dealloc];
[foo release];
玩电脑;您要求 super 解除分配,然后假设实例变量在 super 被解除分配后有效。坏消息。轰隆隆。
这里没有魔法。 foo
是对实例变量的通过 self 的引用。 -dealloc
会破坏 self,因此,foo
不再有效。
(我相信静态分析器会捕捉到这一点。如果没有,它应该会。)
情况 #3:
见#2。这是完全相同的问题。您正在访问不再有效的实例的实例变量。
情况 #4:
self.foo = bar;
与以下内容完全相同:
`[self setFoo: bar];
(除非有任何 setter= 恶作剧)
因此,关键区别在于 -setFoo: 的实现方式(手写或@synthesized)。在您的情况下,它是retain
s 吧。与foo = bar;
不同的是,不会发生保留;它只是对bar
的引用的赋值。
我强烈建议您重新访问 Objective-C 介绍文档。它会有所帮助。但是,我也鼓励您退后一步,认真思考上述情况下的每一行代码到底在做什么。没有魔法,实际行为非常简单。
【讨论】:
以上是关于更具体的通用 Objective-C 内存管理的主要内容,如果未能解决你的问题,请参考以下文章