好的,所以我正在开发iPhone应用程序的一半时间,在内存管理方面我一直磕磕绊绊。
我已经尝试了很多次来理解这一点,并取得了非常有限的成功。我认为自己的智力高于平均水平,但这些东西只是让我不知所措,尽管反复搜索和阅读Apple文档
假设我有一个我正在创建的选择器 - 所以代码
UIPickerView *patientPicker = [[[UIPickerView alloc] init]retain];
//more code here
[self.view addSubView:patientPicker];
然后我用我的选择器做了几件不同的事情。
选择器仅在按下分段控制按钮时出现。分段控件指示使用哪个数据数组来填充选择器。
然而,当我更改分段控件时,我发现它在旧选择器的顶部显示一个新的选择器,而不是更改当前选择器中的数据。
即。分段控制是患者年龄或体重。如果选择年龄,则会出现年龄选择器,如果选择了重量,则会显示相同的重量选择器。但是,如果其中一个选择器已经存在,那么单击备用段不会更改数据,它只会在视图上添加另一个选择器。
当我尝试隐藏拾取器时,我的问题就出现了,因为旧的拾取器仍在下面,我无法隐藏旧的拾取器。
因此,当我点击按钮删除选择器时,旧选择器仍然存在于下方。
我试过了
[patientPicker removeFromSuperView];
但是当我尝试重建我的选择器时,我被告知患者Picker已被解除分配???
同样如此
[patientPicker release];
我知道有人可以告诉我简单的答案,但我真正想要的是对记忆管理的一个非常简单/愚蠢的解释,以便我不必再问。
假装我7岁!
由于
鲍勃
答案 0 :(得分:1)
UIPickerView *patientPicker = [[[UIPickerView alloc] init] retain];
您不/不应执行retain
。 init
调用已经暗示调用者负责创建对象(换句话说,init
隐含了retain
。每release
和init
都需要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)
两种内存管理规则:
new
,alloc init
,retain
或copy
(N.A.R.C。)对象,则必须将其释放。release
该对象。否则返回的方法不归调用者所有,他必须表明他希望让它在对象上调用retain
。请注意,第一条规则会产生第二条规则。一个方法创建一个对象(因此它负责释放它),但是如果方法的结果(返回的对象)在方法的执行中存活(因此它可以传递给调用者),那么所有方法都可以自动释放宾语。自动释放将对象添加到自动释放池中,该池将在将来的某个时刻释放该对象。
示例:
[[MyObject new]; // 1)
[NSString initWithFormat:@"%d",1]; // 2)
[NSString string]; // 3)
1)名称包含新内容,因此需要发布 2)名称包含init,因此需要释放 3)名称不包含任何NARC单词,因此您知道它返回一个自动释放的对象。这意味着如果你打算保留它,你需要保留它,如果你这样做,你需要稍后发布它。否则只需使用它就可以忘掉它。
一些提示:
你的榜样(贾斯汀告诉你的事情):
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
对象)
会有更多类似的惯例,您可以识别所有权;我刚刚记下了我现在想起的内容。