如果我这样做:
@interface RegisterController : UIViewController <UITextFieldDelegate>
{
IBOutlet UITextField *usernameField;
}
Run Code Online (Sandbox Code Playgroud)
而不是这个:
@interface RegisterController : UIViewController <UITextFieldDelegate>
{
UITextField *usernameField;
}
@property (nonatomic, retain) IBOutlet UITextField *usernameField;
Run Code Online (Sandbox Code Playgroud)
会发生什么坏事吗?我知道在第二种情况下,该字段被保留,但是由于笔尖拥有该字段,这是否会有所不同?没有保留,这个领域会消失吗?在什么情况下?第一种情况下的代码工作,想知道这是否是内存管理方面的问题.
Joe*_*orn 71
为了清晰和一致,建议您为所有IBOutlet声明属性.详细信息在" 内存管理编程指南 "中有详细说明.基本要点是,当您的NIB对象被取消归档时,nib加载代码将通过setValue:forKey:来设置所有IBOutlet.当您在属性上声明内存管理行为时,对于发生的事情并不神秘.如果视图被卸载,但您使用了声明为retain的属性,那么您仍然可以获得对文本字段的有效引用.
也许更具体的例子可以说明你应该使用保留属性的原因:
我将对你正在使用的上下文做一些假设 - 我假设上面的UITextField是另一个由UIViewController控制的视图的子视图.我将假设在某些时候,视图不在屏幕上(可能是在UINavigationController的上下文中使用),并且在某些时候您的应用程序会获得内存警告.
因此,假设您的UIViewController子类需要访问其视图以在屏幕上显示它.此时,将加载nib文件,并使用setValue:forKey:由nib加载代码设置每个IBOutlet属性.这里要注意的重要事项是将设置为UIViewController的view属性的顶级视图(将保留此顶级视图)和UITextField,它们也将被保留.如果只是设置它,它将通过nib加载代码保留它,否则属性将保留它.UITextField也将是顶级UIView的子视图,因此它将有一个额外的保留,位于顶级视图的子视图数组中,因此此时文本字段已被保留两次.
此时,如果您想以编程方式切换文本字段,则可以这样做.使用该属性可以使内存管理更清晰; 您只需使用新的自动释放文本字段设置该属性.如果您没有使用该属性,则必须记住将其释放,并可选择保留新属性.此时,对于拥有此新文本字段的人来说有点模棱两可,因为内存管理语义不包含在setter中.
现在假设在UINavigation Controller的堆栈上推送了一个不同的视图控制器,因此该视图不再位于前台.在内存警告的情况下,将卸载此屏幕外视图控制器的视图.此时,顶级UIView的view属性将被清除,它将被释放并取消分配.
因为UITextField被设置为保留的属性,所以UITextField不会被释放,因为它唯一保留的是顶级视图的子视图数组.
相反,如果没有通过属性设置UITextField的实例变量,它也会出现,因为在设置实例变量时,nib加载代码保留了它.
这个亮点的一个有趣点是,因为UITextField还通过属性保留,所以在内存警告的情况下,您可能不希望保留它.因此,您应该在 - [UIViewController viewDidUnload]方法中清除属性.这将取消UITextField上的最终版本并按预期取消分配.如果使用该属性,则必须记住明确释放它.虽然这两个动作在功能上是等同的,但意图是不同的.
如果不是交换文本字段,而是选择从视图中删除它,可能已将其从视图层次结构中删除并将属性设置为nil,或者释放文本字段.虽然在这种情况下可以编写正确的程序,但很容易在viewDidUnload方法中产生过度释放文本字段的错误.过度释放对象是导致崩溃的错误; 将已经为零的属性设置为nil则不是.
我的描述可能过于冗长,但我不想在场景中遗漏任何细节.简单地遵循指南将有助于在遇到更复杂的情况时避免出现问题.
另外值得注意的是,桌面上的Mac OS X上的内存管理行为不同.在桌面上,在没有setter的情况下设置IBOutlet不会保留实例变量; 但如果可用,再次使用setter.
zpa*_*ack 11
从内存管理的角度来看,IBOutlet声明的东西什么都不做(IBOutlet字面意思是#defined什么都没有).将IBOutlet包含在声明中的唯一原因是,如果您打算在Interface Builder中连接它(这就是IBOutlet声明的用途,提示IB).
现在,为实例变量创建@property的唯一原因是,如果您打算以编程方式分配它们.如果你不这样做(也就是说,你只是在IB中设置你的用户界面),那么你是否要创建一个属性并不重要.没理由,IMO.
回到你的问题.如果你只是在IB中设置这个ivar(usernameField),不要打扰属性,它不会影响任何东西.如果你为usernameField创建一个属性(因为你是以编程方式创建它),肯定会为它创建一个属性,并且如果是这样,绝对要使属性保留.
实际上有两种型号:
这些模型是Objective-C 2.0之前的模型,并且继承自Mac OS X.它仍然有效,但您不应声明属性来修改ivars.那是:
@interface StrokeWidthController : UIViewController {
IBOutlet UISlider* slider;
IBOutlet UILabel* label;
IBOutlet StrokeDemoView* strokeDemoView;
CGFloat strokeWidth;
}
@property (assign, nonatomic) CGFloat strokeWidth;
- (IBAction)takeIntValueFrom:(id)sender;
@end
Run Code Online (Sandbox Code Playgroud)
在此模型中,您不保留IBOutlet ivars,但您必须释放它们.那是:
- (void)dealloc {
[slider release];
[label release];
[strokeDemoView release];
[super dealloc];
}
Run Code Online (Sandbox Code Playgroud)
您必须声明IBOutlet变量的属性:
@interface StrokeWidthController : UIViewController {
IBOutlet UISlider* slider;
IBOutlet UILabel* label;
IBOutlet StrokeDemoView* strokeDemoView;
CGFloat strokeWidth;
}
@property (retain, nonatomic) UISlider* slider;
@property (retain, nonatomic) UILabel* label;
@property (retain, nonatomic) StrokeDemoView* strokeDemoView;
@property (assign, nonatomic) CGFloat strokeWidth;
- (IBAction)takeIntValueFrom:(id)sender;
@end
Run Code Online (Sandbox Code Playgroud)
另外,你必须在dealloc中释放变量:
- (void)dealloc {
self.slider = nil;
self.label = nil;
self.strokeDemoView = nil;
[super dealloc];
}
Run Code Online (Sandbox Code Playgroud)
进一步模式,在非脆弱平台中,您可以删除ivars:
@interface StrokeWidthController : UIViewController {
CGFloat strokeWidth;
}
@property (retain, nonatomic) IBOutlet UISlider* slider;
@property (retain, nonatomic) IBOutlet UILabel* label;
@property (retain, nonatomic) IBOutlet StrokeDemoView* strokeDemoView;
@property (assign, nonatomic) CGFloat strokeWidth;
- (IBAction)takeIntValueFrom:(id)sender;
@end
Run Code Online (Sandbox Code Playgroud)
在这两种情况下,都通过调用setValue:forKey:来设置出口.内部运行时(特别是_decodeObjectBinary)检查setter方法是否存在.如果它不存在(只有ivar存在),它会向ivar发送额外的保留.因此,如果没有setter方法,则不应保留IBOutlet.
| 归档时间: |
|
| 查看次数: |
13975 次 |
| 最近记录: |