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

时间:2013-10-27 23:54:35

标签: objective-c cocoa

我有一个类A,它提供了一种获取和设置Foo类型对象的方法。用属性来说,我通常在界面中声明:

@property (nonatomic, strong) Foo * foo;

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

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

似乎我有两个选择:

  1. 声明属性,实现两个访问器,并简单地忽略编译器为_foo创建存储的事实,并且从不使用它。
  2. 在界面中明确声明我的访问者:- (Foo *)foo- (void)setFoo:(Foo *)foo,就像我以前在现代的ObjC中一样。
  3. 第一个在运行时似乎不够优雅,而第二个在声明中看起来不那么优雅(我现在可能会混合使用属性和类似属性的访问器)。

    有没有办法申报一个属性,并将其作为纯粹的声明?

3 个答案:

答案 0 :(得分:9)

在实施文件中使用@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

(注意:回答我自己的问题,因为我在写这个问题时发现了这个问题,看起来很有趣而且非显而易见。)

答案 1 :(得分:5)

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

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

这是根据Apple的官方文档。 Scroll down to "You Can Implement Custom Accessor Methods"

答案 2 :(得分:2)

@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