有人可以解释内存管理

时间:2012-01-11 01:53:07

标签: iphone xcode

好的,所以我正在开发iPhone应用程序的一半时间,在内存管理方面我一直磕磕绊绊。

我已经尝试了很多次来理解这一点,并取得了非常有限的成功。我认为自己的智力高于平均水平,但这些东西只是让我不知所措,尽管反复搜索和阅读Apple文档

假设我有一个我正在创建的选择器 - 所以代码

UIPickerView *patientPicker = [[[UIPickerView alloc] init]retain];
//more code here
[self.view addSubView:patientPicker];

然后我用我的选择器做了几件不同的事情。

选择器仅在按下分段控制按钮时出现。分段控件指示使用哪个数据数组来填充选择器。

然而,当我更改分段控件时,我发现它在旧选择器的顶部显示一个新的选择器,而不是更改当前选择器中的数据。

即。分段控制是患者年龄或体重。如果选择年龄,则会出现年龄选择器,如果选择了重量,则会显示相同的重量选择器。但是,如果其中一个选择器已经存在,那么单击备用段不会更改数据,它只会在视图上添加另一个选择器。

当我尝试隐藏拾取器时,我的问题就出现了,因为旧的拾取器仍在下面,我无法隐藏旧的拾取器。

因此,当我点击按钮删除选择器时,旧选择器仍然存在于下方。

我试过了

[patientPicker removeFromSuperView];

但是当我尝试重建我的选择器时,我被告知患者Picker已被解除分配???

同样如此
[patientPicker release];

我知道有人可以告诉我简单的答案,但我真正想要的是对记忆管理的一个非常简单/愚蠢的解释,以便我不必再问。

假装我7岁!

由于

鲍勃

5 个答案:

答案 0 :(得分:1)

UIPickerView *patientPicker = [[[UIPickerView alloc] init] retain];

不/不应执行retaininit调用已经暗示调用者负责创建对象(换句话说,init隐含了retain。每releaseinit都需要retain

答案 1 :(得分:0)

我估计每次分段控件改变选择时你都会alloc/init。您可以做的是,在vieDidLoad中,执行此操作:

UIPickerView *patientPicker = [[UIPickerView alloc] init;
//more code here
[self.view addSubView:patientPicker];
patientPicker.hidden = YES;
[patientPicker release];

在分段控件上进行选择时,将选择器的隐藏属性设置为NO,并根据选择设置datasource

答案 2 :(得分:0)

这听起来像是工具的工作......是的!命中构建和分析并删除每个问题=)但要理解为什么静态分析器标记你的程序,并了解它可以捕获的相当多的东西,但它可以&#相当多#&# 39; t证明是参考计数不平衡,不会标记这些。然后使用泄漏工具运行并修复所有问题等,如果您遇到解除分配的实例,请运行僵尸工具并解决所有问题。

无论如何,还有更多内容!以下是您的代码的一些要点。

UIPickerView *patientPicker
         = [[[UIPickerView alloc] init]retain]; // << do not retain here. alloc 
                                          // returns an object you must release

[self.view addSubView:patientPicker]; // << self.view will retain its subviews.
                                      // ok, that makes sense that the view
                                      // would want to hold onto a reference to
                                      // ensure the view is not destroyed
                                      // while it's still a subview.

[patientPicker removeFromSuperView]; << the superview will release its subview 

[patientPicker release]; << your life will be easier if you use the accessors

当您处理引用计数时,您需要保留对使用对象的引用。所以,让我们把自动释放池排除在外。仅在需要时使用自动释放将帮助您学习,并使您的一些问题在呼叫站点本地 - 避免在您学习的同时尽可能地调用自动释放。

NSString * a = [[NSMutableString alloc] init]; // << I hold 1 reference
[a length]; // ok
[a retain]; // << I hold 2 references
[a release]; // << I hold 1 reference
[a release]; // << I hold 0 references
[a length]; // expect bad things

现在让我们来说明自动释放池:

NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
NSString * a = [[NSMutableString alloc] init]; // << I hold 1 reference
[a length]; // ok
[a retain]; // << I hold 2 references
[a release]; // << I hold 1 reference
[a autorelease]; // << add a to pool. when pool is destroyed a release message will be sent to a
[a length]; // ok. a is still alive. its release message is deferred until the pool is destroyed
[pool release]; // pool's reference count has reached zero. pool will call [a release]. pool will be destroyed. 
[a length]; // expect bad things

答案 3 :(得分:0)

两种内存管理规则:

  • 如果您是newalloc initretaincopy(N.A.R.C。)对象,则必须将其释放。
  • 当方法的名称以任何单词开头时,表示正在为调用者创建它,调用者在完成对象时有责任release该对象。否则返回的方法不归调用者所有,他必须表明他希望让它在对象上调用retain

请注意,第一条规则会产生第二条规则。一个方法创建一个对象(因此它负责释放它),但是如果方法的结果(返回的对象)在方法的执行中存活(因此它可以传递给调用者),那么所有方法都可以自动释放宾语。自动释放将对象添加到自动释放池中,该池将在将来的某个时刻释放该对象。

示例:

[[MyObject new]; // 1)
[NSString initWithFormat:@"%d",1]; // 2)
[NSString string]; // 3)

1)名称包含新内容,因此需要发布 2)名称包含init,因此需要释放 3)名称不包含任何NARC单词,因此您知道它返回一个自动释放的对象。这意味着如果你打算保留它,你需要保留它,如果你这样做,你需要稍后发布它。否则只需使用它就可以忘掉它。

一些提示:

  • 尝试对称保留/释放,这样您就不会忘记要发布的内容和位置。示例:如果您保留在init上,则在dealloc上发布。对于viewDidLoad / viewDidUnload也是如此。
  • 如果您可以选择,请不要在内存问题时滥用自动释放功能,以便尽快恢复记忆。滥用自动释放也是您不了解内存管理的一个标志。

你的榜样(贾斯汀告诉你的事情):

UIPickerView *patientPicker = [[UIPickerView alloc] init]; // 1)
[self.view addSubView:patientPicker]; // 2)
[patientPicker release]; // 3)

1)我们调用alloc init,因此一旦你完成它就知道这个对象需要释放 2)addSubView调用内部保留。为什么?当您收到一个对象而您打算保留它时,您表示该意图称为保留,这也使您有责任释放它。当UIView被释放时,它的实现也会释放它的子视图以平衡之前由addSubView完成的保留 3)我们将不再使用它,所以我们称之为发布。现在,self.view是对象的所有者。

作为练习,尝试为变量实现自己的setter和getter,然后运行Build and Analyze来查看Xcode对它的看法。

答案 4 :(得分:0)

如果您拥有所有权,请专注于所有权;你必须release对象。如果您没有所有权,则不敢release


id myObject;
myObject = [abc retain] =&gt;你是老板

myObject = [[abc alloc] init] =&gt;你是老板

myObject = [abc copy] =&gt;你是老板


myObject = [[[abc alloc] init] autorelease] =&gt;你不是主人 (你把autorelease放在所有权的任何地方)

myObject = [abc xxxWithYYY] =&gt;你不是主人 (作为约定,返回对象的方法总是给出autorelease对象)


会有更多类似的惯例,您可以识别所有权;我刚刚记下了我现在想起的内容。