简体   繁体   English

(iPhone)基本内存管理问题

[英](iphone) basic memory management question

I have used following 2 patterns to create a view. 我使用了以下2种模式来创建视图。

@property (retain, nonatomic) SomeView* someView;

...

// First pattern
self.someView = [[SomeView alloc] initWithFrame frame];

// Second pattern
SomeView* aSomeView = [[SomeView alloc] initWithFrame];
self.someView = aSomeView;
[aSomeView release];

Now, looking back at this code, the first pattern's method should be changed to 现在,回头看这段代码,第一个模式的方法应该更改为

self.someView = [[[SomeView alloc] initWithFrame frame] autorelease];

shouldn't it? 不是吗

I feel dumb :( 我觉得很蠢:(

Look at it like this: 像这样看它:

[[SomeView alloc] initWithFrame: frame];

The above line creates an object and gives it a retain count of 1. 上面的行创建一个对象,并为其保留计数为1。

self.someView = [[SomeView alloc] initWithFrame: frame];

This line leaves it with a retain count of two, because the someView property is declared with retain: 这行保留的计数为2,因为someView属性是用keep声明的:

@property (**retain**, nonatomic) SomeView* someView;

So, doing it this way leaves your someView property pointing to an object with retain count of 2. You can do it this way if you add an autorelease call to it: 因此,以这种方式进行操作会使您的someView属性指向保留计数为2的对象。如果向其添加自动释放调用,则可以通过以下方式进行操作:

self.someView = [[[SomeView alloc] initWithFrame: frame] autorelease];

Your second pattern is better, if you ask me. 如果您问我,您的第二种模式会更好。 You create an object with a retain count of one. 您创建一个保留计数为1的对象。 You assign it to a retaining property (now it has a retain count of 2) and then you release the original variable, leaving the object again with a retain count of 1. It's three lines where you might want only one, but it makes sense in the right context. 您将其分配给一个retaining属性(现在它的保留计数为2),然后释放原始变量,再次使对象的保留计数为1。在三行中,您可能只需要一行,但这很有意义在适当的情况下。 Additionally, it's usually best to avoid using autorelease outside of an alloc or copy method since its usually an indication you don't fully understand memory management in Obj-C. 此外,通常最好避免在alloc或copy方法之外使用自动释放,因为这通常表明您不完全了解Obj-C中的内存管理。

And as a commenter said in the comments to the question, don't feel dumb. 正如评论员在对问题的评论中所说的那样,不要感到愚蠢。 None of this is intuitive at first. 起初这些都不是直观的。 Nobody picks up a guitar and plays like Hendrix their first time. 没有人第一次拾起吉他,像Hendrix一样演奏。

Yes, you are right. 是的,你是对的。 autorelease means "release a bit later". autorelease意味着“稍后释放”。

Yes, I think you should change that. 是的,我认为您应该更改它。 With self.someView = you are calling the setter which increases the retain count. 使用self.someView =您将调用setter来增加保留计数。

Now, looking back at this code, 1's method should be changed to self.someView = [[[SomeView alloc] initWithFrame frame] autorelease]; 现在,回头看一下这段代码,应该将1的方法更改为self.someView = [[[[SomeView alloc] initWithFrame frame] autorelease]; shouldn't it? 不是吗

correct 正确

a) 一种)

SomeView * view = [[SomeView alloc] initWithFrame:frame];
self.someView = view;
[view release], view = nil;

b) b)

self.someView = [[[SomeView alloc] initWithFrame:frame] autorelease];

many people prefer b, simply because it is less to type. 许多人更喜欢b,仅仅是因为它的类型较少。

i prefer an approach similar to a because: 我更喜欢类似于a的方法,因为:

  • defects (such as over-releasing) are often exposed near the call site, rather than when the pool is destroyed (this often means you have to load up Instruments in Zombie mode to locate the callsite) 缺陷(例如过度释放)通常会在呼叫站点附近暴露出来,而不是在池被销毁时暴露出来(这通常意味着您必须以Zombie模式加载Instruments才能找到呼叫站点)
  • it performs better and minimizes memory usage (in general, but not much in this specific case) 它的性能更好,并最大程度地减少了内存使用(通常,但在此特定情况下不多)
  • you have more opportunity to check for invalid states and results 您有更多机会检查无效状态和结果
  • you have a chance to init/configure the view/object for its usage before adding it to self, which is usually preferred 您有机会在将视图/对象添加到自身之前初始化/配置视图/对象的用途,通常这是首选

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM