IBOutlets,实例variables和属性:最佳实践
今天我已经做了各种关于宣布IBOutlet和实例variables,pipe理它们,使用正确的访问器并正确释放它们的最佳实践的研究。 我在那里,但我有一些利基问题,我希望有人能够build议最佳实践。 我会将它们格式化为代码并对问题进行评论以便于理解。 我已经排除了一些我认为不相关的明显的部分,可以安全地假设工作(像预处理器的东西,@end,所需的实现方法等)。
MyViewController.h
@class OtherViewController; @interface MyViewController : UIViewController { NSString *_myString; BOOL _myBOOL; } // The first two properties aren't declared in the interface // above as per best practices when compiling with LLVM 2.0 @property (nonatomic, retain) OtherViewController *otherViewController; @property (nonatomic, retain) UIButton *myButton; @property (nonatomic, copy) NSString *myString; @property (readwrite) BOOL myBOOL;
MyViewController.m
@implementation MyViewController // Synthesizing IBOutlets on iOS will cause them to be // retained when they are created by the nib @synthesize otherViewController; @synthesize myButton; // Assign instance variables so as to force compiler // warnings when not using self.variable @synthesize myString = _myString; @synthesize myBOOL = _myBOOL; - (void)viewDidLoad { // QUESTIONS: // 1. Ignoring convenience methods, can you still alloc and init in dot notation // even when it's being properly synthesized? self.myString = [[NSString alloc] initWithString:@"myString"]; self.myString = existingNSStringObject; // 2. Should you always call methods for IBOutlets and instance variables using dot notation? // Is there any difference seeing as these aren't directly invoking setters/getters? [self.myButton setText:self.myString]; [myButton setText:self.myString]; [self.otherViewController.view addSubview:mySubview]; [otherViewController.view addSubview:mySubview]; [self.myButton setAlpha:0.1f]; [myButton setAlpha:0.1f]; self.myButton.alpha = 0.1f; myButton.alpha = 0.1f; // 3. How fussy are scalar variables in terms of getters and setters, // given that there is a @synthesize declaration for them? self.myBOOL = YES; myBOOL = NO; if(self.myBOOL) { ... } if(myBOOL) { ... } // 4. On instantiation of new view controllers from NIBs, should you use // dot notation? (I haven't been doing this previously). otherViewController = [[OtherViewController alloc] initWithNibName:@"OtherView" bundle:nil]; self.otherViewController = [[OtherViewController alloc] ... ] } - (void)viewDidUnload { // 5. Best practice states that you nil-value retained IBOutlets in viewDidUnload // Should you also nil-value the other instance variables in here? self.otherViewController = nil; self.myButton = nil; self.myString = nil; } - (void)dealloc { [otherViewController release]; [myButton release]; [_myString release]; }
我总是声明并显式设置一个属性的底层实例variables。 在前面做了一些工作,但是在我看来,明确地区分variables和属性并一目了然地了解类有哪些实例variables是值得的。 我也join实例variables名称,所以如果我不小心inputproperty
而不是object.property
,编译器会object.property
。
-
调用alloc / init将创build一个保留计数为1的对象。您的合成属性也将保留该对象,从而在释放内存时导致内存泄漏(除非您之后立即释放属性,但forms不正确)。 更好地分配/并释放在一个单独的行上的对象。
-
点符号与调用
[self setObject:obj]
效果相同。 不使用点符号直接访问底层实例variables。 在init
和dealloc
,总是直接访问实例variables,因为访问方法可以包含在创build或销毁对象时无效的额外操作(例如键值观察通知)。 所有其他时间使用合成的访问器方法。 即使你现在没有做什么特别的事情,稍后你可能会重写这些方法来改变variables被设置的情况。 -
标量以同样的方式工作,只有你不必太担心记忆。
-
一个访问合成的访问方法,另一个直接访问实例variables。 再次看到问题一和二,并注意内存泄漏!
-
视图控制器可能再次被推到屏幕上,在这种情况下,你的
viewDidLoad
方法将被第二次调用。 如果您在viewDidLoad中设置初始值,请继续并将您的属性设置为零。 这对于使用大量内存并且不会影响视图状态的属性是有意义的。 另一方面,如果您希望该属性持续存在,直到您确定不再需要该属性,请在init
方法中创build该属性,并在释放之前不要释放它。
1)你误解了@synthesize。 @synthesize与对象无关。 它只是告诉编译器根据@property声明中使用的选项生成getter和setter方法
//在iOS上合成IBOutlets会导致它们
//由nib创build时保留
这些出口不被保留(出口只是接口生成器的通知,不影响代码),当使用@synthesize生成的setter时, 对象被保留。 当笔尖被加载时,加载系统调用你生成的setter。
2)决定是否在目标C中使用访问器与在任何其他面向对象语言中决定使用访问器没有区别。 这是一个风格,需要和健壮的select。 访问者作为IBOutlet使用没有任何区别。
但是在目标CI中,build议您不要在两个地方使用访问器:dealloc和var的访问器方法本身。
如果你在init中使用访问器,那么你需要小心你的保留计数。
self.myString = [[NSString alloc] initWithString:@"myString"];
这条线泄漏内存。 使用你的副本访问器保留对象,所以你应该在创build它之后在这里释放它。
3)不确定你是什么意思的挑剔。 可能看到答案2)
4)见2),注意内存pipe理。 如果你调用alloc / init,你现在负责释放对象 – 这完全独立于访问器和dealloc使用的保留/释放。
5)不,你不应该在viewDidUnload中删除其他实例variables。 即使视线消失,您的控制器也会保持其状态。 viewDidUnload仅用于在控制器的视图当前不在屏幕上时清除潜在的内存繁重的视图对象。
考虑一个导航控制器。 视图控制器1在堆栈上,然后视图控制器2被按下,现在可见。 如果内存条件变低,系统可能试图卸载视图控制器1的视图,然后调用viewDidUnload。
然后popup视图控制器2不会再创build视图控制器1对象,但它会加载视图控制器1的视图并调用viewDidLoad。
重新评论
2)完全正确 – 你可以在你的alloc / init和assignment之后立即使用一个方便的构造函数或释放,或者在块退出之前释放,或者自动释放。 你select的主要是风格问题(尽pipe有些人会反对autorelease – 但不是我!)
3)有标量访问器 – 你已经在你的代码中创build了一些
@property (readwrite) BOOL myBOOL;
这将在您的类上创build方法myBOOL和setMyBOOL。
请记住,点符号没有什么特别之处。 这只是一个方便,当编译代码时,myObject.property与[myObject property]完全等价,myObject.property = x与[myObject setProperty:x]完全等价。 使用点符号纯粹是一种风格select。
- 点符号和括号符号几乎相同。
- 通过
self.myVariable
你正在访问实例variablesmyVariable
属性的getter和myVariable
你正在访问本地variables。 他们不是一回事。 - 您可以通过重写方法和特定的某些条件来自定义setter和getters。
- 查看第一个答案(括号是首选 – 更好地理解代码)
- 最好做一个单独的方法。
喜欢:
- (void) releaseOutlets { self.firstOutlet = nil; self.mySecondOutlet = nil; …………………… self.myLastOutlet = nil; }
然后在viewDidUnload
和dealloc
方法中调用这个方法。
希望能帮助到你 !