Iphone 如果我不';我不能保留出口吗?

Iphone 如果我不';我不能保留出口吗?,iphone,retain,Iphone,Retain,如果我这样做: @interface RegisterController : UIViewController <UITextFieldDelegate> { IBOutlet UITextField *usernameField; } @接口注册表控制器:UIViewController { IBOutlet UITextField*usernameField; } 与此相反: @interface RegisterController : UIViewControl

如果我这样做:

@interface RegisterController : UIViewController <UITextFieldDelegate>
{
    IBOutlet UITextField *usernameField;
}
@接口注册表控制器:UIViewController
{
IBOutlet UITextField*usernameField;
}
与此相反:

@interface RegisterController : UIViewController <UITextFieldDelegate>
{
    UITextField *usernameField;
}
@property (nonatomic, retain) IBOutlet UITextField *usernameField;
@接口注册表控制器:UIViewController
{
UITextField*用户名字段;
}
@属性(非原子,保留)IBOutlet UITextField*usernameField;

会发生什么坏事吗?我知道在第二种情况下,字段是保留的,但是由于nib拥有该字段,这会使情况有所不同吗?田地会不会在没有土地的情况下消失?在什么情况下?第一种情况下的代码有效,我想知道这是否是内存管理方面的问题。

好的,在第二种情况下,您为特定的IBOutlet添加了一个getter/setter方法。每当您添加getter/setter方法时,您(几乎总是)希望将其设置为保留以解决内存管理问题。我认为提出你的问题的更好方式是:

@interface RegisterController : UIViewController <UITextFieldDelegate>
{
IBOutlet UITextField *usernameField;
}
@property (nonatomic) IBOutlet UITextField *usernameField;
@接口注册表控制器:UIViewController
{
IBOutlet UITextField*usernameField;
}
@属性(非原子)IBOutlet UITextField*usernameField;

@接口注册表控制器:UIViewController
{
IBOutlet UITextField*usernameField;
}
@属性(非原子,保留)IBOutlet UITextField*usernameField;
在这种情况下,那么是的,您需要添加一个retain,因为它会影响内存管理。即使它可能没有任何影响,但如果您以编程方式添加和删除IBOutlet,可能会遇到问题


作为一般规则:每当您有一个IBOutlet时,总是添加一个@property(带有retain)

在开始使用属性提供的访问器之前,这两个接口定义的工作方式没有任何区别

在这两种情况下,您仍然需要在dealloc或viewDidUnload方法中释放IBOutlet并将其设置为nil

IBOutlet指向在XIB文件中实例化的对象。该对象由XIB文件的文件所有者对象(通常是IBOutlet在其中声明的视图控制器)拥有

由于该对象是在加载XIB后创建的,因此其保留计数为1,并由文件所有者拥有,如上所述。这意味着文件所有者负责在解除分配时释放该对象


添加带有retain属性的属性声明只需指定setter方法应保留传入以进行设置的对象,这是正确的方法。如果未在属性声明中指定retain,则IBOUTLE可能会指向一个可能不再存在的对象,因为该对象已由其所有者,或在程序生命周期的某个点自动释放。保留它会阻止对象被释放,直到你处理完它。

从内存管理的角度来看,声明某个东西IBOutlet不会起任何作用(IBOutlet字面上定义为“无”)。将IBOutlet包含在声明中的唯一原因是您是否打算在Interface Builder中连接它(这就是IBOutlet声明的目的,对IB的提示)

现在,为实例变量创建@property的唯一原因是您是否打算以编程方式分配它们。如果您不这样做(也就是说,您只是在IB中设置UI),则无论您是否创建属性都无关紧要。在我看来,没有理由这样做


回到你的问题上来。如果你只是在IB中设置这个ivar(usernameField),不要为这个属性操心,它不会影响任何事情。如果你确实为usernameField创建了一个属性(因为你是通过编程创建的),一定要为它创建一个属性,如果是,一定要保留该属性。

为了清晰一致,建议您为所有iboutlet声明属性。 详细信息在中详细说明。基本要点是,当您的NIB对象未归档时,NIB加载代码将通过并使用setValue:forKey.设置所有IBoutlet。当您在属性上声明内存管理行为时,发生了什么并不神秘。如果视图被卸载,但您使用了已声明为retain,您仍然拥有对textfield的有效引用

也许可以用一个更具体的例子来说明为什么应该使用保留财产:

我将对您工作的上下文做一些假设——我将假设上面的UITextField是另一个视图的子视图,该视图由UIViewController控制。我将假设在某个点上,该视图不在屏幕上(可能在UINavigationController的上下文中使用),并且在某个时候应用程序会收到内存警告

所以,假设您的UIViewController子类需要访问其视图才能在屏幕上显示它。 此时,nib文件将被加载,每个IBOutlet属性将由nib加载代码使用setValue:forKey进行设置。这里需要注意的重要内容是将设置为UIViewController视图属性的顶级视图(将保留此顶级视图)和UITextField,它也将被保留。如果只是简单地设置它,它将由nib加载代码在其上放置一个retain,否则属性将保留它。UITextField也将是顶级UIView的子视图,因此它将有一个额外的retain,位于顶级视图的子视图数组中,因此在这一点上文本字段已保留两次

此时,如果您希望以编程方式切换文本字段,则可以这样做。在此处,使用属性可以更清楚地进行内存管理;您只需使用新的自动释放文本字段设置属性。如果您没有使用该属性,则必须记着释放它,并可以选择保留新字段。此时,它有点像至于谁拥有这个新的文本字段,我们并不清楚,因为内存管理语义并不一致
@interface RegisterController : UIViewController <UITextFieldDelegate>
{
IBOutlet UITextField *usernameField;
}
@property (nonatomic, retain) IBOutlet UITextField *usernameField;
@interface StrokeWidthController : UIViewController {
    IBOutlet UISlider* slider;
    IBOutlet UILabel* label;
    IBOutlet StrokeDemoView* strokeDemoView;
    CGFloat strokeWidth;
}
@property (assign, nonatomic) CGFloat strokeWidth;
- (IBAction)takeIntValueFrom:(id)sender;
@end
- (void)dealloc {
    [slider release];
    [label release];
    [strokeDemoView release];
    [super dealloc];
}
@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
- (void)dealloc {
    self.slider = nil;
    self.label = nil;
    self.strokeDemoView = nil;
    [super dealloc];
}
@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