xcode 何时覆盖目标 c 吸气剂

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/9797809/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-14 23:43:54  来源:igfitidea点击:

When to override objective c getters

objective-ciosxcodepropertiesgetter-setter

提问by PostCodeism

Within the last year, I've been working with other people on some Objective-C projects for the first time.

在去年,我第一次与其他人一起在一些 Objective-C 项目上工作。

Occasionally (and increasingly) I'm seeing other people overriding getter/accessor methods, AND containing implementation code in this method! To me this is crazy town, as this is the whole point of having a setter...it also means that the property being set in the setter will just be overridden in the getter, and therefor pointless.

偶尔(并且越来越多)我看到其他人覆盖了 getter/accessor 方法,并且在这个方法中包含了实现代码!对我来说,这是一个疯狂的小镇,因为这是拥有 setter 的全部意义……这也意味着在 setter 中设置的属性将在 getter 中被覆盖,因此毫无意义。

Are these people behaving badly, or am I the one who's missing something? Is there EVER a need to override a synthesized property's getter method?

是这些人行为不端,还是我遗漏了什么?是否需要覆盖合成属性的 getter 方法?

Example:

例子:

@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;
}

UPDATE:

更新:

Ok width is a bad example. Too many people are getting caught up on the semantics of "what the variable is" and "don't include get in objective-c accessors". So I've updated the above example to ignore the irrelevant semantics, and concentrate on the concept. The concept being...is there any example when you'd want to override the GETTER(not setter, getter only. I override the setter many times, this question is about the getter)?

好的宽度是一个不好的例子。太多人被“变量是什么”和“不包括在objective-c访问器中获取”的语义所困扰。所以我更新了上面的例子,忽略不相关的语义,专注于概念。这个概念是......当你想覆盖GETTER(不是 setter,只有 getter。我多次覆盖 setter,这个问题是关于 getter 的)时,有什么例子吗?

Returning another property such as layer (as mentioned below) is a genuine example. But more specifically is there ever a need to SETthe property in a GETTER? This is some of the weirdness that I'm seeing, so i've updated the getter above to pull a value from the NSUserDefaults to aid my point...

返回另一个属性,如层(如下所述)是一个真实的例子。但更具体地说,是否需要在GETTER 中设置属性?这是我看到的一些奇怪之处,所以我更新了上面的 getter 以从 NSUserDefaults 中提取一个值来帮助我的观点......

回答by iccir

First, Cocoa naming conventions would call the getter -width, not -getWidth. "Get" is used to fill passed in arguments:

首先,Cocoa 命名约定会调用 getter -width,而不是-getWidth. “Get”用于填充传入的参数:

- (void) getWidth:(CGFloat *)outWidth
{
    if (outWidth) *outWidth = _width;
}

That said, back to your original question:

也就是说,回到你最初的问题:

In the old days, before @propertyand @synthesize, we would have to write our accessors manually as you did above.

在过去,在@property和之前@synthesize,我们必须像上面那样手动编写我们的访问器。

There are other occasions where you would want to manually write an accessor, however.

但是,在其他情况下,您可能希望手动编写访问器。

One common one is to delay initialization until a value is needed. For example, say that there is an image which takes awhile to generate. Each time you modify a property that would alter the image, you don't want to redraw the image immediately. Instead, you could defer the draw until the next time somebody asks:

一种常见的方法是延迟初始化,直到需要一个值。例如,假设有一个图像需要一段时间才能生成。每次修改会改变图像的属性时,您都不想立即重绘图像。相反,您可以将抽奖推迟到下次有人问:

- (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;
    }
}

Another use is to forward the implementation of the accessor/mutator to another class. For example, UIViewforwards many of its properties to backing CALayer:

另一个用途是将访问器/修改器的实现转发到另一个类。例如,UIView将其许多属性转发给 backing 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]; }


Update to asker's update:

更新提问者的更新:

In your update, it looks like the code in question is either trying to persist the value of width using NSUserDefaults, or it is trying to allow for users to specify a custom value to override all returned widths. If the latter, your example is fine (although I would limit this practice as it could cause confusion to newcomers).

在您的更新中,看起来有问题的代码要么尝试使用 NSUserDefaults 保留宽度值,要么尝试允许用户指定自定义值来覆盖所有返回的宽度。如果是后者,则您的示例很好(尽管我会限制这种做法,因为它可能会给新手造成混淆)。

If the former, you want to load the value from NSUserDefaults once, and save a new value back to NSUserDefaults in the setter. For example:

如果是前者,您想从 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

The _width ivar is being used as a cache. The truth is stored in NSUserDefaults.

_width ivar 被用作缓存。真相存储在 NSUserDefaults 中。

Note: I'm using NSUserDefaults in this example since you used it in yours. In practice, I prefer to not mix NSUserDefault with my accessors ;)

注意:我在这个例子中使用 NSUserDefaults,因为你在你的例子中使用了它。实际上,我不喜欢将 NSUserDefault 与我的访问器混合使用 ;)

回答by bryanmac

The first issue is you don't want to use getWidth. The pattern in objC is name and setName. Do not use getName. It messes up binding and KVO.

第一个问题是您不想使用 getWidth。objC 中的模式是 name 和 setName。不要使用 getName。它搞砸了绑定和 KVO。

Also, if it's just setting/getting the iVar, there's no reason to override. If you're doing extra processing/validation then it may be Ok to override.

此外,如果它只是设置/获取 iVar,则没有理由覆盖。如果您正在进行额外的处理/验证,则可以覆盖。

EDIT:

编辑:

You should also try to avoid setting data and doing heavy processing in the getter. A getter is supposed to encapsulate some state and return data. The expectation is that it's very light weight. Heavy processing and/or modifications should be done in methods or setters. For example, folks set debug watches on getters and don't expect heavy processing and modification of state.

您还应该尽量避免在 getter 中设置数据和进行繁重的处理。getter 应该封装一些状态并返回数据。期望它的重量非常轻。应该在方法或设置器中进行大量处理和/或修改。例如,人们在 getter 上设置调试监视,并且不期望对状态进行大量处理和修改。

回答by nacho4d

How about the case when you create your property object lazily? I use this pattern very often, also used in Xcode's CoreData template, etc.

懒惰地创建属性对象的情况如何?我经常使用这种模式,也在Xcode的CoreData模板等中使用。

- (NSString *)string
{
    if (!_string) {
        // Create the string property lazily
        // Create is using some other internal, etc values
        _string = [NSString alloc] initWith...]
    }
    return _string;
}

Also:

还:

- (void)setString:(NSString *)string
{
    if (![string isEqualToString:_string]) {
        // Probably you want to make your property observable here too :)

        [_setString release];
        _setString = [string retain];

        // Update other things that depend on _string for example redraw the view, etc
        [self setNeedsDisplay];
    }
}

回答by Patrick T Nelson

There are plenty of reasons for override both getter and setter methods, for example I override setter methods when I make custom UITableViewCell objects, so that I can set a property, and then within that setter method, it will automatically update a label or something within the cell, instead of me having to call an update function after setting the property.

覆盖 getter 和 setter 方法的原因有很多,例如我在创建自定义 UITableViewCell 对象时覆盖了 setter 方法,这样我就可以设置一个属性,然后在该 setter 方法中,它会自动更新标签或其中的内容单元格,而不是我必须在设置属性后调用更新函数。

You may want to overwrite a getter if you want to store information differently than receiving it, an example might be a phone number object, where you might store it as 5551234567 and it will automatically be retrieved as 555-123-4567 or something like that. I rarely override getter methods myself, but I override setter methods quite frequently.

如果您想以不同于接收信息的方式存储信息,您可能需要覆盖一个 getter,一个例子可能是一个电话号码对象,您可以将它存储为 5551234567,它会自动被检索为 555-123-4567 或类似的东西. 我自己很少覆盖 getter 方法,但我经常覆盖 setter 方法。

回答by ThomasW

This is a perfectly acceptable practice in object oriented programming. However, one needs to be aware of the side effects. You shouldn't do something like network access in a setter method, for example.

这是面向对象编程中完全可以接受的做法。但是,需要注意副作用。例如,您不应该在 setter 方法中执行诸如网络访问之类的操作。

However, in the code you list above since they don't do anything different from what the synthesized methods do, there is no reason to include the implementations. They just clutter up the code.

但是,在上面列出的代码中,因为它们与合成方法所做的没有任何不同,所以没有理由包含实现。他们只是把代码弄乱了。