更具体的通用 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 保留barfoo 分配给bar

分配foo = barfoo = [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 包含对该代码行之前的保留对象的引用。引用将被覆盖。如果您需要在覆盖引用之前releasefoo,请这样做,但这与分配正交。

情况 #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)。在您的情况下,它是retains 吧。与foo = bar; 不同的是,不会发生保留;它只是对bar 的引用的赋值。

我强烈建议您重新访问 Objective-C 介绍文档。它会有所帮助。但是,我也鼓励您退后一步,认真思考上述情况下的每一行代码到底在做什么。没有魔法,实际行为非常简单。

【讨论】:

以上是关于更具体的通用 Objective-C 内存管理的主要内容,如果未能解决你的问题,请参考以下文章

[精通Objective-C]内存管理

Objective-C内存管理教程和原理剖析(转)

Objective-C的内存管理

Objective-C内存管理之MRC

Objective-C内存管理之MRC

[学习笔记—Objective-C]《Objective-C-基础教程 第2版》第九章 内存管理