10

我想在公共接口中保护对 NSMutableArray 的访问

我试图通过在公共接口中将属性定义为 NSArray 并在私有接口中定义为 NSMutableArray 来做到这一点,如下所示:

@interface Order : NSObject
@property (readonly, strong, nonatomic) NSArray* comments;
@end

@interface Order()
@property (readwrite, strong, nonatomic) NSMutableArray* comments;
@end

但这不起作用 - 所以我必须在公共接口 NSMutableArray 中定义属性:

@interface Order
@property (strong, nonatomic) NSMutableArray* comments;
@end

目标是为 API 客户端提供对注释的只读访问权限以及addObject:对实现中方法的完全访问权限。

所以定义目标更清晰:

  1. 客户端应该可以访问属性作为 NSArray 而不能访问突变方法。
  2. 客户不应该有能力更新评论以指向新的价值。
  3. 该解决方案必须在不创建额外结构和数组复制的情况下完成。

所以简单的问题是是否有可能使属性的公共定义更通用(NSArray 而不是 NSMutableArray)。

有没有其他干净的方法可以达到目标,或者我必须在任何地方使用 NSMutableArray?

解析度

在查看了我最初的问题和答案后,我意识到我想在公共接口中使用更通用的类 NSArray 并在实现中使用 NSMutableArray - 但对于一个属性来说这是不可能的。所以答案是不可能的。

所以我将只使用 NSMutableArray 的单个属性,而不需要任何额外的保护。

但是,如果您真的更喜欢保护而不是简单和高效,我也会选择最合适的答案。

4

5 回答 5

14

如果您只想允许客户端读取数组,则不需要公共属性。

只需创建一个返回私有可变数组副本的访问器方法:

@interface Order : NSObject
- (NSArray *)allComments;
@end

@implementation Order ()
@property (nonatomic, strong) NSMutableArray * comments;
@end

@implementation Order

@synthesize comments;

- (NSArray *)allComments
{
    return [[self comments] copy];
}

@end

这种模式可以在例如NSView:中看到,constraints并且subviews在内部是可变的,但仅通过返回非可变数组的单个方法公开以供读取。

于 2013-03-31T18:40:39.007 回答
4

一种解决方案是将属性声明为只读的NSArray. 然后在您的实现中,基于NSMutableArray.

在.h中:

@interface Order : NSObject
@property (readonly, strong, nonatomic) NSArray* comments;
@end

在他们中:

@interface Order()
@property (strong, nonatomic) NSMutableArray* internalComments;
@end

不要合成 readonly 属性,而是编写:

- (NSArray *)comments {
    return [self.internalComments copy];
}

在 .m 中,您可以使用 .m 完成所有操作self.internalComments

于 2013-03-31T18:42:08.137 回答
2

如果您的用例可以接受,一个更清洁的解决方案是将属性声明为NSArray,同时使用NSMutableArray. 客户端可以通过简单地将数组转换为可变数组来从技术上修改数组,但您明确表示这样做是一个坏主意。

A@property只是两个方法的包装器,getter 和 setter,它们通常由存储变量支持。实现此解决方案的最简单方法是:

@interface Order : NSObject
{
    NSMutableArray *_comments;
}

@property (readonly, strong, nonatomic) NSArray *comments;

- (void)addComment:(Comment *)comment;

@end

@implementation Order
@synthesize comments=_comments; // Can be omitted if you use Xcode 4.4+

- (void)addComment:(Comment *)comment
{
    [_comments addObject:comment];
}

@end

如果您希望用户能够替换整个数组 ( order.comments = ...),请删除readonly属性上的属性并覆盖该-setComments:方法:

- (void)setComments:(NSArray *)array
{
    [_comments release]; // Can be omitted if you are using ARC
    _comments = [array mutableCopy];
}

值得注意的是,由于 Objective-C 是一种动态语言,因此不可能完全阻止某人访问变量,因为如果你真的想在你的事情中四处寻找,你可以直接与运行时接口或通过他们的选择器调用方法'不应该。你真正能做的就是清楚地表明这样做是一个坏主意。

于 2013-10-04T13:11:41.370 回答
1

两种解决方案:

  1. 返回数组的非可变副本 - 客户端一次性获取所有评论。
  2. 返回评论和个人评论的数量。

任你选择,两者都有争论,这取决于什么适合你:

@interface Order : NSObject

// solution one - return a copy
@property (readonly, strong, nonatomic) NSArray* comments;

// solution two - return individual comments
@property (readonly) NSUInteger commentCount;
- (id) comment:(NSUInteger)number;

@end

@interface Order()

// internal property - mutable
@property (readwrite, strong, nonatomic) NSMutableArray* privateComments;

@end

@implementation Order

// solution one - return a copy
- (NSArray *) comments            { return [self.privateComments copy]; }

// solution two - return individual comments
- (NSUInteger) commentCount       { return self.privateComents.count; }
- (id) comment:(NSUInteger)number { return self.privateComment[number]; }

@end
于 2013-03-31T19:02:50.373 回答
0

如果您根本不希望客户端能够设置此属性,则在公共接口中将其声明为readonly. 如果您不希望客户端能够改变客户端可以读取的数组,则将其声明为 NSArray。同时,在你这边,你是readwritecopy。通过成为readwrite您可以获取一个mutableCopy(这将是一个 NSMutableArray),进行更改,然后再次设置属性;通过成为copy您确保客户端始终看到 NSArray。

所以,客户:

NSArray* arr = order.comments; // ok
[arr addObject: @"ha"]; // no, can't
order.comments = someOtherArray; // no, can't

内部订单:

NSMutableArray* marr = self.comments.mutableCopy;
[marr addObject: @"ha"];
self.comments = marr; // and it is magically turned back into an NSArray
于 2013-03-31T18:28:54.113 回答