Pos*_*ism 3 xcode properties objective-c getter-setter ios
在过去的一年里,我第一次与其他人一起开展了一些Objective-C项目.
偶尔(并且越来越多)我看到其他人重写getter/accessor方法,并且在这个方法中包含实现代码!对我来说,这是一个疯狂的城镇,因为这是拥有一个二传手的全部意义......这也意味着设置在setter中的属性将在getter中被覆盖,因此毫无意义.
这些人表现得很糟糕,还是我错过了什么?是否需要覆盖合成属性的getter方法?
例:
@synthesize width;
- (CGFloat)width {
NSNumber *userWidth = [[NSUserDefaults standardUserDefaults] objectForKey:@"USER_WIDTH"];
if (userWidth != nil)
{
width = [NSNumber floatValue];
}
//Shouldn't the above lines be done in the SETTER? I have SET the property!
//Why would I ever need to write anything BUT the below line??
return width;
}
- (void)setWidth:(CGFloat)newWidth {
//THIS is where you do the the setting!
width = newWidth;
}
Run Code Online (Sandbox Code Playgroud)
更新:
好宽度是一个坏例子.太多的人都陷入了"变量是什么"和"不包括get-objective-c访问器"的语义.所以我更新了上面的例子来忽略不相关的语义,并专注于这个概念.这个概念是...当你想要覆盖GETTER时没有任何例子(不是setter,只有getter.我多次覆盖setter,这个问题是关于getter的)?
返回另一个属性,如图层(如下所述)是一个真实的例子.但更具体地说,是否需要在GETTER中设置属性?这是我所看到的一些奇怪之处,所以我更新了上面的getter来从NSUserDefaults中提取一个值以帮助我的观点......
icc*_*cir 12
首先,Cocoa命名约定会调用getter -width,而不是-getWidth."Get"用于填充传递的参数:
- (void) getWidth:(CGFloat *)outWidth
{
if (outWidth) *outWidth = _width;
}
Run Code Online (Sandbox Code Playgroud)
那说,回到你原来的问题:
在过去@property和之前@synthesize,我们必须像上面那样手动编写访问器.
但是,在其他情况下,您可能需要手动编写访问器.
一种常见的方法是延迟初始化直到需要一个值.例如,假设有一个图像需要一段时间才能生成.每次修改将改变图像的属性时,您都不希望立即重绘图像.相反,你可以推迟抽奖,直到下一次有人问:
- (UIImage *) imageThatTakesAwhileToGenerate
{
if (!_imageThatTakesAwhileToGenerate) {
// set it here
}
return _imageThatTakesAwhileToGenerate;
}
- (void) setColorOfImage:(UIColor *)color
{
if (_color != color) {
[_color release];
_color = [color retain];
// Invalidate _imageThatTakesAwhileToGenerate, we will recreate it the next time that the accessor is called
[_imageThatTakesAwhileToGenerate release];
_imageThatTakesAwhileToGenerate = nil;
}
}
Run Code Online (Sandbox Code Playgroud)
另一个用途是将accessor/mutator的实现转发给另一个类.例如,UIView将其许多属性转发给支持CALayer:
// Not actual UIKit implementation, but similar:
- (CGRect) bounds { return [[self layer] bounds]; }
- (void) setBounds:(CGRect)bounds { [[self layer] setBounds:bounds]; }
- (void) setHidden:(BOOL)hidden { [[self layer] setHidden:hidden]; }
- (BOOL) isHidden { return [[self layer] isHidden]; }
- (void) setClipsToBounds:(BOOL)clipsToBounds { [[self layer] setMasksToBounds:clipsToBounds]; }
- (BOOL) clipsToBounds { return [[self layer] masksToBounds]; }
Run Code Online (Sandbox Code Playgroud)
更新到asker的更新:
在您的更新中,看起来有问题的代码是尝试使用NSUserDefaults保持宽度值,或者它试图允许用户指定自定义值来覆盖所有返回的宽度.如果是后者,你的例子很好(虽然我会限制这种做法,因为它可能会引起新人的混淆).
如果是前者,则需要从NSUserDefaults加载一次值,并将新值保存回setter中的NSUserDefaults.例如:
static NSString * const sUserWidthKey = @"USER_WIDTH";
@implementation Foo {
CGFloat _width;
BOOL _isWidthIvarTheSameAsTruthValue;
}
@synthesize width = _width;
- (CGFloat) width
{
if (!_isWidthIvarTheSameAsTruthValue) {
NSNumber *userWidth = [[NSUserDefaults standardUserDefaults] objectForKey:sUserWidthKey];
if (userWidth != nil) _width = [NSNumber doubleValue];
_isWidthIvarTheSameAsTruthValue = YES;
}
return _width;
}
- (void) setWidth:(CGFloat)newWidth
{
if (_width != newWidth) {
_width = newWidth;
NSNumber *userWidthNumber = [NSNumber numberWithDouble:_width];
[[NSUserDefaults standardUserDefaults] setObject:userWidthNumber forKey:sUserWidthKey];
_isWidthIvarTheSameAsTruthValue = YES;
}
}
@end
Run Code Online (Sandbox Code Playgroud)
_width ivar用作缓存.真相存储在NSUserDefaults中.
注意:我在此示例中使用的是NSUserDefaults,因为您在自己的身上使用过NSUserDefaults.在实践中,我更喜欢不将NSUserDefault与我的访问者混合;)
第一个问题是你不想使用getWidth.objC中的模式是name和setName.不要使用getName.它弄乱了绑定和KVO.
此外,如果只是设置/获取iVar,则没有理由覆盖.如果您正在进行额外的处理/验证,那么覆盖可能是好的.
编辑:
您还应该尝试避免在getter中设置数据和进行繁重的处理.getter应该封装一些状态并返回数据.期望它的重量非常轻.重复处理和/或修改应在方法或设定者中进行.例如,人们在getter上设置调试监视,并且不期望重处理和修改状态.
| 归档时间: |
|
| 查看次数: |
9161 次 |
| 最近记录: |