使用 alloc/retain/release 的可能场景?
我使用ojective c已经快一周了,我主要是一个c++编码员。在我阅读了 Apple 的内存管理指南后,我尝试将我在 C++ 中的内存使用风格带入 Objective C...我试图总结这些场景,我想如果我遵循这些说明,我就不会犯内存错误。如果我错了,请告诉我:)
我会尽量不使用autorelease,就个人而言,通过使用autorelease,在某些自动释放池耗尽之前可能总会有一些冗余内存。我只会使用release,这确保我的应用程序在任何时候都使用最小的内存。
Apple 所说的另一件事(我用自己的话来描述)是:每次添加保留/分配/复制时,我都应该在某处添加释放。
以下是我总结的所有场景:
在同一个函数中:分配一个对象,使用它,然后释放它
在类的init函数中,分配一个对象对象,在类的dealloc函数中,释放对象
当需要拥有一个指针时,应该保留< /em> 类方法中的输入指针(假设方法 A),然后释放 类的 dealloc 函数中的指针班级。
我发现objective c中使用retain的时机和c/c++中使用memcpy的时机是一样的,所以我取retain< /em> 作为“内存高效副本”
如果要将输入保留指针设置为成员指针变量,则应先释放成员指针。 因此,在 case[3] 中,类的 init 中的 alloc 与方法 A 中的 release 配对, 并且方法A中的retain与dealloc
中的release配对,返回一个指针作为返回值。老实说,当我使用c++时,我从来没有做过这样的事情。如果返回一个成员指针就可以了,因为有人会处理它:
-(UIButton*) getTheButton() { 返回按钮; }
但是返回指向本地分配对象的指针确实很糟糕:
-(UIButton*) getTheButton() { UIButton* myButton = [[UIButton alloc] init]; 返回我的按钮; //糟糕的! }
有人可能会说在这种情况下我应该使用 autorelease,但我只是想通过使用以下方法来绕过该解决方案:我只会返回成员指针,或者我不会返回指针,我只会对给定的输入指针进行操作。< /p>
-void operaOnTheButton(UIButton* 按钮) { [按钮释放]; 按钮= [[UIButton分配]初始化]; }
因此,如果我按照上面的内存使用说明进行操作,如果出现任何问题,请告诉我。
谢谢:D
I have been using ojective c for almost a week, and I am mainly a c++ coder. After I read Apple's memory management guide, I try to bring my memory usage style in c++ into objective c... I tried to conclude these scenarios, I think I won't make memory mistake if I follow these instructions. Please kindly let me know if I am wrong :)
I will try not to use autorelease, personally speaking, by using autorelease, there might always be some redundent memory before certain auto release pool is drained. I will only use release, which make sure my application uses minimum memory at any time.
Another thing Apple says, which I describe with my own words, is: everytime I add an retain/alloc/copy, I should add a release somewhere.
Here are all the scenarios I conclude:
In the same function: alloc an object, use it, and release it
In the init function of a class, alloc an object, in the dealloc function of the class, release the object
When it's necessary to own a pointer, one should retain an input pointer in a method of a class(let's say method A), and then release the pointer in the dealloc function of the class.
I found that the timing of using retain in objective c is the same to the timing of using memcpy in c/c++, so I take retain as a "memory efficient copy"
If the input retained pointer is to set to a member pointer variable, then one should release the member pointer first.
So in case[3], alloc in init of the class is paired with release in method A,
and the retain in method A is paired with the release in deallocReturn a pointer as return value. Honestly speaking I never do such things when I use c++. It's OK if to return a member pointer, coz someone will take care of it:
-(UIButton*) getTheButton() { return theButton; }
But it's really terrible to return a pointer to a locally allocated object:
-(UIButton*) getTheButton() { UIButton* myButton = [[UIButton alloc] init]; return myButton; //TERRIBLE! }
Someone might say I should use autorelease in that case, but I simply want to bypass that solution by using this: I will only return member pointers, or I will not return pointers, I will only operate on given input pointers.
-void operateOnTheButton(UIButton* button) { [button release]; button = [[UIButton alloc] init]; }
So, please kindly let me know if there is any problem if I follow the memory usage instructions above.
Thanks :D
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
在一个重要场景中,您必须使用
autorelease
。如果您分配/保留/复制一个对象,然后将其返回给其他代码,那么您拥有该对象,但无法释放
它,因为其他代码需要使用它(否则你不会退回它)。在这种情况下,您必须通过向对象发送
autorelease
消息来负责对象的释放,从而确保它最终会被释放。这正是 NSString 的stringWithString:
等基础方法所做的事情。您不必release
从该方法获得的字符串对象,因为您没有分配/保留/复制它,但如果该方法没有为您自动释放它,它将在 < code>[池耗尽] 并成为内存泄漏。确保您了解引用计数的工作原理。
release
减少对象的引用计数。当计数达到 0 时,对象就会被销毁。alloc
和copy
创建一个引用计数为 1 的对象。retain
将接收对象的引用计数增加 1。对于每个 alloc/retain/复制 必须有一个版本
。 1 上,1 下。因此,当您返回创建的对象并将控制权传递给被调用者时,就会使一对一等式失去平衡,因为您无法
释放
它。这就是为什么有autorelease
。它不会减少接收者的引用计数器,因此不存在被销毁的危险,但是当池耗尽时,池中的每个对象都会为每个autorelease
获取一条release
消息> 它已经收到,恢复平衡(除非一个对象被故意保留,这样它就可以在耗尽时幸存下来,在这种情况下,被调用者需要稍后释放它)。至于第 4 点,如果您自动释放,那么您的第二个示例就很好,基础类中这种技术的示例比比皆是。每个数据类(如 NSString、NSArray、NSDictionary 等)都有返回本地分配的对象指针的方法。它们通常采用
thisWiththat:
形式,例如stringWithstring:
或dictionaryWithContentsOfFile:
。后者将分配一个字典对象,用文件的内容填充它,自动释放它,并返回一个指向您的指针。它称为工厂函数。在 obj-c 和 java 中非常常见的模式。您的第三个代码示例稍后将导致运行时错误。您正在释放一个不属于您的对象。所有者不会期望您
释放
它,这可能意味着它将收到太多release
消息,从而导致运行时错误。如果您没有分配/保留/复制它,则您不拥有它,因此您不应释放它。There is one important scenario where you must use
autorelease
. If you alloc/retain/copy an object and then return it to some other code you own that object, but you can'trelease
it because other code needs to use it (or you wouldn't have returned it).In this situation you must take responsibility for the object's release by sending it an
autorelease
message, thereby ensuring it will eventually be released. This is exactly what foundation methods like NSString'sstringWithString:
do. You don't have torelease
a string object you get from this method because you didn't alloc/retain/copy it, but if the method hadn't autoreleased it for you it would survive the[pool drain]
and become a memory leak.Make sure you understand how reference counting works.
release
decrements an object's reference count. When the count reaches 0 the object is destroyed.alloc
andcopy
create an object with a ref count of 1.retain
increments the receiving object's ref count by 1. For each alloc/retain/copy there must be onerelease
. 1 up, 1 down.So when you return an object you created, passing control to the callee, you unbalance the 1 to 1 equation because you have no way to
release
it. That's why there'sautorelease
. It doesn't decrement the receiver's ref counter, so there's no danger it will be destroyed, but when the pool is drained each object in the pool gets onerelease
message for eachautorelease
it has received, restoring the balance (unless an object was intentionally retained so it would survive the drain, in which case the callee would need torelease
it later).As for point 4, your second example is fine if you
autorelease
, examples abound of this technique in the foundation classes. Every data class like NSString, NSArray, NSDictionary, etc. has methods that return locally allocated object pointers. They usually have the formthisWiththat:
, likestringWithstring:
ordictionaryWithContentsOfFile:
. The latter would allocate a dictionary object, populate it with the contents of the file, autorelease it, and return a pointer to you. Its called a factory function. Very common pattern in obj-c, java too.You're third code example will cause a runtime error later. You are releasing an object you don't own. The owner will not expect you to
release
it which will likely mean it will receive one too manyrelease
messages, causing a runtime error. If you didn't alloc/retain/copy it, you don't own it so you shouldn't release it.自动释放部分不正确。如果您使用工厂方法,它不以 alloc/retain/copy 开头。你必须自动释放它。调用者不会创建该对象,因此调用者不能也不应该释放它。因此,如果调用者想要做某事并确保对象存在,则调用者必须自行保留它们。
好的解决方案是:
然后在调用者中:
您不能这样做:
原因:operateOnTheButton 不拥有该按钮,它不应该释放该按钮。如果我向您发送一个按钮,然后在通话后我收到另一个按钮,会发生什么情况? operaOnButton 不分配/保留/复制参数。它无权释放它。
它可能会给您带来一些问题:
1/ EXEC_BAD_ACCESS:当您在不拥有该对象的方法中释放时,有人可能仍然使用它
2/ 内存仍然泄漏:释放并不意味着您立即删除内存。你只需将retainCount减1。这意味着如果传递时按钮对象的retainCount为2,释放它只会使你的retainCount为1,并不会删除该对象的内存
3/你的按钮对象也是泄漏:没有人可以确保你的按钮对象被释放。你拥有它,所以你必须自己释放它,否则,按钮对象是泄漏的
The autorelease part is incorrect. If you do a factory method, which doesn't start with alloc/retain/copy . You have to autorelease it. The caller doesn't create the object, so the caller can not and should not release it. So, if the caller wants to do something and make sure the objects there, caller has to retain them itself.
The good solution is :
then in the caller:
You can not do this:
The reason: operateOnTheButton does not own the button, it shouldn't release the button. What happens if I send you a button and then after the calling, I have another button. The operateOnButton doesn't alloc/retain/copy the parameter. It has no right to release it.
It can create some problems for you:
1/ EXEC_BAD_ACCESS: someone may still use it when you release inside a method that you don't own the object
2/ memory still leaks: release doesn't mean you delete the memory immediately. You just decrement the retainCount by 1. Which means if when passed the button object has retainCount of 2, releasing it will only make your retainCount 1, doesn't remove the memory of the object yet
3/ your button object is also leak: noone can make sure that your button object is released. You own it, so you have to release it yourself, otherwise, the button object is leak
这种情况很正常,但有些人(包括我自己)更喜欢在
alloc
同一行自动释放,以避免意外忘记释放。init
通常不会调用alloc
。在对象上创建时,首先调用alloc
,然后在新分配的实例上调用init
。这个场景非常正确。然而,保留并不复制。
在 Objective-C 中,对象总是通过它们的指针来引用,这与 C++ 不同。如果您正在编写一个返回字符串的方法,那么您将返回一个
NSString*
,而不是NSString
结构本身。下面的代码片段实际上会导致内存泄漏:
button
是一个局部变量,当它超出范围时,它会泄漏,因为它还没有被释放。我不太确定这个operateOnTheButton:
方法应该做什么。This scenario is normal, but some (myself included) prefer to autorelease on the same line as
alloc
to avoid accidentally forgetting to release.init
does not normally callalloc
. When creating on object,alloc
is called first, theninit
is called on the newly allocated instance.This scenario is pretty much correct. Retaining doesn't make a copy, however.
In Objective-C objects are always referred to by their pointers, which is different to C++. If you're writing a method that returns an string then you return an
NSString*
, never theNSString
struct itself.The following snippet of code will actually cause a memory leak:
button
is a local variable, and when it goes out of scope it will leak because it hasn't been released. I'm not quite sure what thisoperateOnTheButton:
method is supposed to do.为什么要避免自动释放?这是它应该完成的方式...
另外,一些建议:
很多人在 iPhone 上犯的一个错误是在 UIViewController 的 viewDidLoad 方法中分配内存,然后在 dealloc 方法而不是 viewDidUnload 方法中释放它。
始终考虑一个视图可以多次加载。
Why do you want to avoid AutoRelease? It's the way it should be done...
Also, some advice:
One error that a lot of people do on the iPhone is allocate memory in a UIViewController's viewDidLoad method and then release it in the dealloc method instead of the viewDidUnload method.
Always consider that a view can be loaded more than once.
“在类的 init 函数中,分配一个对象,在类的 dealloc 函数中,释放该对象”
首先:没有函数,是类的一部分。是的,您可以编写 C 函数。您可以编写在实例上运行的 C 函数。但是,如果您编写一些 -(foo)doSomethings (甚至 +(foo)doSomethings),您会得到一个消息处理程序。您可以通过发送消息来使用它们。
这就是为什么您不能从 -(id)init 消息中分配实例的原因:init 想要与内存和其中超类的实例“对话”。由于您没有分配此空间和功能,因此您将出现一些狂野的内存位置或(更有可能)为零。
另一方面,您释放对象的方式将根本不会释放任何内容。因为dealloc是在对象被销毁时发送到对象的。但是,由于您不释放它(因为您想在 dealloc 中执行此操作),因此该对象永远不会被放置在“天堂之门”列表中:它会保持保留计数为 1(或更大),直到您的应用程序终止并将分配内存的对象踢回操作系统的空闲池。 dealloc 消息不会由您发送。 dealloc 仅用于内存管理例程。 (我想,如果最超级的 NSObject(您的实例父母和祖父母的根)将收到释放并且它看到保留计数应低于 1,则发送此消息。)
如果您如果您确实想要在 Objective C 中进行内存管理,您必须编写自己的框架;你自己的“符合 C++ 的 Cocoa”。恕我直言。
问候
“In the init function of a class, alloc an object, in the dealloc function of the class, release the object”
First: there are no functions, being some part of a class. Yes, you can write C-functions. You can write C-functions operating on instances. But what you get if you write some of this -(foo)doSomethings (or even +(foo)doSomethings) is a message handler. And you use them by sending messages.
This is the reason why you can’t alloc an instance from within an -(id)init message: init wants to “talk” to the memory and the instance of the superclass within. As you didn’t alloc this space and functionality, you will either some wild memory location or (more probable) to nil.
On the other hand your way to release an object will release nothing at all. Because dealloc ist sent to the object when it will be destroyed. But as you don’t release it (as you want to do that inside dealloc), the object will never be placed on the list to “heavens gate”: it keeps an retain-count of 1 (or greater) until your application dies and kicks the objects allocated memory back to the free pool of the OS. The dealloc-message is not to be sent by you. The dealloc ist just for the memory management routines. (I suppose, this message is sent if the most super NSObject, the root of your instances parents and grandparents, will receive a release and it sees, that the retain count should go below 1.)
If you really want to have your memory management in Objective C, you will have to write your own frameworks; your own “C++ conforming Cocoa”. IMHO.
Greetings