我已经使用ojective近一个星期了,我主要是一个c ++编码器。在我阅读了Apple的内存管理指南之后,我尝试将c ++中的内存使用方式带入目标c ...我试图总结这些场景,我想如果我遵循这些说明,我不会犯错误。如果我错了,请告诉我。)
我会尝试不使用自动释放,个人来说,通过使用自动释放,在某个自动释放池耗尽之前可能总会有一些冗余内存。我只会使用release,这可以确保我的应用程序在任何时候都使用最少的内存。
用我自己的话说,苹果说的另一件事是:每次我添加一个retain / alloc / copy,我都应该在某处添加发布。
以下是我总结的所有情景:
在同一个函数中: alloc 一个对象,使用它,然后发布
在类的 init 函数中, alloc 一个对象,在该类的 dealloc 函数中,发布对象
当需要拥有指针时,应该保留类的方法中的输入指针(假设方法A ),然后< em> release 该类的 dealloc 函数中的指针。
我发现在目标c中使用 retain 的时间与在c / c ++中使用 memcpy 的时间相同,所以我采用 retain < / em>作为“内存高效副本”
如果输入保留指针要设置为成员指针变量,则应首先释放成员指针。 所以在案例[3]中,类的 init 中的 alloc 与方法A 中的 release 配对, 并且方法A 中的保留与 dealloc
返回指针作为返回值。老实说,当我使用c ++时,我从未做过这样的事情。如果要返回一个成员指针就可以了,因为有人会照顾它:
-(UIButton*) getTheButton() {
return theButton;
}
但是返回指向本地分配对象的指针真的很糟糕:
-(UIButton*) getTheButton() {
UIButton* myButton = [[UIButton alloc] init];
return myButton; //TERRIBLE!
}
有人可能会说我应该在这种情况下使用自动释放,但我只是想通过使用它来绕过该解决方案:我只会返回成员指针,或者我不会返回指针,我只会对给定的输入指针进行操作。 / p>
-void operateOnTheButton(UIButton* button) {
[button release];
button = [[UIButton alloc] init];
}
所以,如果我按照上面的内存使用说明,请告诉我是否有任何问题。
谢谢:D
答案 0 :(得分:9)
有一个重要的情况是必须使用autorelease
。如果您分配/保留/复制一个对象,然后将其返回到拥有该对象的其他代码,但您不能release
它,因为其他代码需要使用它(或者您不会回来的。)
在这种情况下,必须通过发送autorelease
消息来对该对象的发布负责,从而确保它最终会被释放。这正是NSString的stringWithString:
这样的基础方法所做的。您没有release
从此方法获得的字符串对象,因为您没有分配/保留/复制它,但如果该方法没有为您自动释放它,它将在{{1}之后存活并成为内存泄漏。
确保您了解引用计数的工作原理。 [pool drain]
递减对象的引用计数。当计数达到0时,对象被销毁。 release
和alloc
创建一个引用计数为1的对象。copy
将接收对象的引用计数增加1.对于每个alloc / retain / copy,必须有一个retain
}。 1上,1下。
因此,当您返回您创建的对象时,将控制传递给被调用者,您会使1到1的等式失衡,因为您无法release
它。这就是release
的原因。它不会减少接收者的ref计数器,所以它不会被破坏,但是当池耗尽时,池中的每个对象都会收到一条autorelease
消息,它已经收到了每个release
,恢复平衡(除非有意保留一个对象,以便它能够在排水中存活,在这种情况下被调用者需要稍后autorelease
。
至于第4点,如果你release
,你的第二个例子就没问题,在基础课中这个例子比比皆是。 NSString,NSArray,NSDictionary等每个数据类都有返回本地分配的对象指针的方法。它们的格式通常为autorelease
,如thisWiththat:
或stringWithstring:
。后者将分配一个字典对象,用文件内容填充它,自动释放它,并返回一个指向你的指针。它被称为工厂功能。 obj-c中的常见模式,也是java。
您是第三个代码示例,稍后会导致运行时错误。您正在发布一个您不拥有的对象。所有者不会指望你dictionaryWithContentsOfFile:
它可能意味着它会收到太多release
个消息,从而导致运行时错误。如果你没有分配/保留/复制它,你就不拥有它,所以你不应该发布它。
答案 1 :(得分:2)
自动释放部分不正确。如果您执行的工厂方法不是以alloc / retain / copy开头的。你必须自动发布它。调用者不会创建对象,因此调用者不能也不应该释放它。因此,如果调用者想要做某事并确保那里的对象,调用者必须自己保留它们。
好的解决方案是:
-(UIButton*) getTheButton() {
UIButton* myButton = [[UIButton alloc] init];
return [myButton autorelease]; // if you don't do autorelease, memory will leak
}
然后在来电者中:
- (void)caller {
UIButton *button = [[self getTheButton] retain];
}
你不能这样做:
-void operateOnTheButton(UIButton* button) {
[button release];
button = [[UIButton alloc] init];
}
原因:operateOnTheButton没有自己的按钮,它不应该释放按钮。如果我发给你一个按钮然后在通话后会发生什么,我有另一个按钮。 operateOnButton不分配/保留/复制参数。它没有权利发布它。 它可能会给你带来一些问题:
1 / EXEC_BAD_ACCESS:当您在不拥有该对象的方法内发布时,某人仍可能使用它
2 /内存仍然泄漏:释放并不意味着您立即删除内存。你只需将retainCount减1.这意味着如果传递按钮对象时retainCount为2,释放它只会使你的retainCount为1,不会删除对象的内存
3 /您的按钮对象也是泄漏:没有人可以确保您的按钮对象被释放。你拥有它,所以你必须自己释放它,否则,按钮对象是泄漏
答案 2 :(得分:1)
这种情况很正常,但有些人(包括我自己)喜欢在与alloc
相同的行上自动发布,以避免意外忘记释放。
init
不通常会调用alloc
。在对象上创建时,首先调用alloc
,然后在新分配的实例上调用init
。
这种情况非常正确。但是,保留不会复制。
在Objective-C中,对象总是由它们的指针引用,这与C ++不同。如果您正在编写一个返回字符串的方法,那么您将返回NSString*
,而不是NSString
结构本身。
以下代码片段实际上会导致内存泄漏:
-(void) operateOnTheButton:(UIButton*)button {
[button release];
button = [[UIButton alloc] init];
}
button
是一个局部变量,当它超出范围时,它会泄漏,因为它尚未被释放。我不太确定这个operateOnTheButton:
方法应该做什么。
答案 3 :(得分:0)
为什么要避免自动释放?这是它应该做的方式......
另外,一些建议:
许多人在iPhone上做的一个错误是在UIViewController的viewDidLoad方法中分配内存,然后在dealloc方法而不是viewDidUnload方法中释放它。
始终考虑可以多次加载视图。
答案 4 :(得分:0)