子类属性

时间:2012-09-17 18:56:56

标签: objective-c properties subclass

我想以抽象的方式做以下事情:

// .h
@interface SomeObject : NSObject
@property (readonly) NSArray myProperty;
@end

// .m
@interface SomeObject ()
@property (readwrite) NSMutableArray myProperty;
@end

@implementation SomeObject
@end

根据Subclassing with Properties in the Mac Developer Library部分,允许使用readonly覆盖readwrite个属性。什么不起作用是使用属性类型的子类。 我使用NSMutableArray作为示例,但它可以是任何其他类/子类组合。

根据继承规则,它应该没问题。 readonly只生成getter,也允许返回子类对象。

当您需要某些属性的子类类型供内部使用时,如何处理此类情况?

一种丑陋的方式如下,但我想避免这种情况,因为这意味着在访问子类方法时我不能使用self. getter和setter。

// .h
@interface SomeObject : NSObject
@property (readonly) NSArray myProperty;
@end

// .m
@implementation SomeObject {
    NSMutableArray _myProperty;
}
@synthesize myProperty = _myProperty;
@end

2 个答案:

答案 0 :(得分:4)

编辑(根据您的修改):编辑后的具体情况是一种特殊且常见的情况(如果它们可以同时进行),需要仔细考虑。< / p>

这是一个特殊的原因是因为子类是暴露类的可变形式。调用者可能会在收到后不会更改。但是如果你交回你的内部对象,那么它可能会发生变异。您有几种选择:

  • 返回不可变副本。这通常是小型馆藏的最佳解决方案。这当然是最简单的。但是如果可能经常调用访问器并且集合很大,那么它可能会非常昂贵。

  • 使您的内部属性不可变。如果对属性的请求比对属性的更改更常见,则在对象变异时(使用arrayByAddingObject:subarrayWithRange:等)重新创建对象会更有效。

    < / LI>
  • 警告调用者返回的对象可能会改变.... uggh ...我在一个需要性能的情况下完成了这个,但这很危险。

  • 我从来没有这样做过,但你也可以这样创建自己的copy-on-write:直接返回可变版本并标记一个现在“脏”的标志。当内部需要变异时,制作一个可变副本并将其存储在您的属性中(放弃旧的集合)。这似乎有很多复杂性,但在某些情况下可能会有用,特别是如果读取和写入倾向于分开聚集(大量读取后跟大量写入)。


基于NSObject与NSString的

OLD ANSWER:

我认为你的目标是让myProperty成为一种不透明的类型,而不是泄漏它是NSString的事实?或许这样你以后可以改变主意实际实现的方式?有几个选择。最简单的方法是定义类型id。然后在内部将其视为字符串。 id可以是任何东西。它通常优先于NSObject*

如果您想在内部获得更多类型安全性,那么您可以使用另一个类型为NSString的名称创建一个私有属性,并将其返回myProperty,如下所示:

SomeObject.h

@interface SomeObject : NSObject
@property (readonly) id myProperty;
@end

SomeObject.m

@interface SomeObject ()
@property (readwrite) NSString *myInternalProperty;
@end

@implementation SomeObject
- (id)myProperty {
  return myInternalProperty;
}
@end

您可以使用的另一种隐藏技术(如果隐藏对您来说非常重要)是一个子类。例如:

SomeObject.h

@class MyOpaque;
@interface SomeObject : NSObject
@property (readonly) MyOpaque *myProperty;
@end

SomeObject.m

@interface MyOpaque : NSString
@end
@implementation MyOpaque
@end

@implementation SomeObject
@end

由于调用者没有@interface的{​​{1}}定义,因此如果没有编译器警告,他就无法向其发送消息。

答案 1 :(得分:-7)

  

当您需要某些子类类型时,如何处理此类情况?   内部使用的财产?

属性明确不适用于内部使用,它们是公共接口的成员。

如果您需要内部值,请定义成员字段并覆盖属性的setter以设置内部值。