2

我想以抽象的方式执行以下操作:

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

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

@implementation SomeObject
@end

根据Mac 开发人员库中的使用属性子类化部分,允许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
4

2 回答 2

4

编辑(基于您的编辑):您在编辑后的具体情况有点特殊和常见(如果可以同时出现),需要仔细考虑。

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

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

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

  • 警告调用者返回的对象可能会改变......呃......我在一个需要性能的情况下这样做了,但这很危险。

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


基于 NSObject 与 NSString 的旧答案:

我假设您的目标是myProperty成为某种不透明的类型,而不是泄露它是NSString? 也许这样您以后可以改变主意,了解它的实际实施方式?有几个选项。最简单的方法是将其定义为 type id。然后在内部将其视为字符串。id可以是任何东西。它通常比NSObject*.

如果你想要更多的内部类型安全,那么你可以创建一个具有另一个类型名称的私有属性,NSString并像这样返回它myProperty

一些对象.h

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

一些对象.m

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

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

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

一些对象.h

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

一些对象.m

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

@implementation SomeObject
@end

由于调用者没有 的@interface定义MyOpaque,因此他无法在没有编译器警告的情况下向其发送消息。

于 2012-09-17T19:49:25.473 回答
-7

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

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

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

于 2012-09-17T19:00:37.210 回答