objective-C属性也定义为实例变量

objective-C属性也定义为实例变量,objective-c,properties,instance-variables,Objective C,Properties,Instance Variables,我已经定义了 @interface FooObject : NSObject @property (nonatomic, readonly) Foo *foo; @end 然后在实施过程中: @implementation FooObject { Foo *_foo; ... } 但是,我的理解是,创造财产 @property (nonatomic, readonly) Foo *foo; 在接口中,还创建 _foo 所以我的问题是,这样做有什么好处,可能的好处是什么。没有好处。只需删除

我已经定义了

@interface FooObject : NSObject
@property (nonatomic, readonly) Foo *foo;
@end
然后在实施过程中:

@implementation FooObject {
Foo *_foo;
...
}
但是,我的理解是,创造财产

@property (nonatomic, readonly) Foo *foo;
在接口中,还创建

_foo

所以我的问题是,这样做有什么好处,可能的好处是什么。

没有好处。只需删除
Foo*\u Foo。在这种情况下是多余的。

您会问:

这样做有什么好处吗

不,手动声明实例变量没有任何好处。事实上,这样做有一些缺点,因为您很容易输入错误的ivar名称(或错误地使用
@synthesis
语句),最终得到两个ivar,一个是您手动创建的,另一个是为您合成的。它只是引入了可能的印刷错误导致难以诊断的bug的可能性

有几个注意事项:

  • 这种手动定义IVAR以支持属性的模式有点过时,可以追溯到Objective-C编译器为您合成这些IVAR之前

    值得注意的是,如果您使用的是旧的Objective-C编译器(例如,特别是那些在非macOS平台上试验Objective-C或使用旧版本的Xcode),编译器可能无法为您自动合成这些IVAR,您必须手动合成。尽管如此,您还是可以使用
    @synthesis
    指令让编译器为您执行此操作,而不是手动声明ivar。只有在使用
    @synthesis
    指令引入之前的极旧编译器时,才需要手动声明ivar

  • 如果您自己实现了所有访问器方法(即只读属性的getter或读写属性的getter和setter),编译器将不会为您合成ivar。这种想法可能是,如果您正在编写自己的访问器方法,您可能会让那些访问器做一些与常规ivar交互以外的事情,因此它不会为您合成ivar

    在这个场景中,如果需要,您必须自己手动合成ivar。例如,考虑这个类:

    @interface Foo: NSObject
    @property (nonatomic) NSInteger bar;
    @end
    
    如果同时实现两个访问器:

    - (void)setBar:(NSInteger)bar {
        // do something, and then update ivar
        _bar = bar;
    }
    
    - (NSInteger)bar {
        // do something, and then retrieve ivar
        return _bar;
    }
    
    然后您必须自己在
    @实现中手动合成ivar:

    @synthesize bar = _bar;
    
    注意,我没有手动定义
    \u bar
    ivar,但我还是让编译器来定义,但我必须使用
    @synthesis
    指令手动启动它

    我上面的示例具有读写属性。同样的问题也适用于只读属性,您已经为其实现了自己的自定义getter

    显然,如果您没有实现自定义访问器方法(我们通常没有),您就不必手动合成ivar。只需定义
    @属性
    ,就完成了


  • 还要确保在
    分机上为
    foo
    设置
    readwrite
    。因此,您可以在
    实现中设置它的值
    @theCoderGuy-您可以这样做,但从技术上讲您不必这样做。您的
    @实现
    理论上可以直接更新ivar,而不需要设置器。但我同意,当您有一个属性,希望在内部享受setter方法的好处,但不将其作为公共接口的一部分公开时,这是一个很好的模式。good point@Rob!如果您不打算使用setter,则不必强制使用:)