如何声明@property但阻止创建其 ivar



我有类A,它公开了一种获取和设置类型为 Foo 的对象的方法。用属性术语来说,我通常在界面中声明这一点:

@property (nonatomic, strong) Foo * foo;

这(在现代 ObjC 中)生成访问器和 ivar,_foo用于存储。

如果我想在访问器中执行自定义工作,我可以自己实现其中一个或两个。但是,如果我不仅想做定制工作,而且实际上不想要ivar怎么办?换句话说,我正在对Foo对象做其他事情,比如将其来回传递给我组成的另一个内部对象。实际上,我根本不需要在A实例中为foo保留存储。

似乎我有两个选择:

  1. 声明属性,实现两个访问器,并简单地忽略编译器为_foo创建存储的事实,并且永远不要使用它。
  2. 显式声明我的访问器:在界面中- (Foo *)foo- (void)setFoo:(Foo *)foo,就像我在前现代 ObjC 中一样。
第一个在运行时似乎不优雅

,第二个在声明中似乎不优雅(我现在可能混合了属性和类似属性的访问器)。

有没有办法声明属性并将其纯粹用作声明?

在实现文件中使用 @dynamic 关键字。通常对@dynamic的讨论将其描述为在编译时不创建访问器。通常不提到的是,这也具有不执行任何操作来为属性创建存储的效果,而这正是在这种情况下所期望的。

@implementation A
@dynamic foo;
- (Foo *)foo 
{
   // get a Foo from somewhere and return it.
}
- (void)setFoo:(Foo *)foo
{
   // do something with foo
}
@end

(注意:回答了我自己的问题,因为我在写问题时发现了这一点,它似乎很有趣且不明显。

如果您同时覆盖 setter 和 getter,并且不在 setter 和 getter 中使用变量,则不会创建变量。

例如,如果你有一个类,你想要一个firstNamelastName属性,但可能还有一个fullName属性的settergetter,如果你的fullName setter 只是将字符串解析为 firstNamelastName 并将这些属性设置为该属性(并且从不将完整的字符串存储到 fullName 变量中), 而你的fullName getter只是returns串联的firstName + lastName,从不使用fullName变量,永远不会创建一个。

这是根据苹果的官方文档。 向下滚动到"您可以实现自定义访问器方法"

@dynamic可能是

要走的路。

但是,您还可以通过其他两种方式执行此操作:

  1. 未实现的类别

    可以使用未实现的类别来声明属性,但不能获取后备存储:

    @interface Foo : NSObject
    @end
    @interface Foo (UnimplementedProperties)
    @property (strong) id bar;
    @end
    @implementation Foo
    @end
    

    通过不声明类别(@implementation Foo (UnimplementedProperties))的实现,属性不会被合成。

  2. 一个协议

    可以在协议上声明属性,然后使类符合该协议。 这与未实现的类别具有相同的效果:声明了方法,但不合成了属性。

    @protocol FooProperties <NSObject>
    @property (strong) id bar;
    @end
    @interface Foo : NSObject <FooProperties>
    @end
    

最新更新