Objective-C中如何用NSMutableArray实现只读NSArray属性?
解决思路与方案
方案1:类扩展重声明属性(首选)
这是Objective-C里最贴合封装原则的优雅实现:在你的类.m文件顶部添加类扩展,把公开的routeContext属性重新声明为readwrite,同时指定其类型为NSMutableArray:
// 你的类.m文件开头 @interface YourClass () @property (readwrite, nonnull) NSMutableArray<String *> *routeContext; @end @implementation YourClass - (instancetype)init { self = [super init]; if (self) { _routeContext = [NSMutableArray array]; } return self; } // 内部直接用self.routeContext做增删操作,比如: - (void)addRouteItem:(NSString *)item { [self.routeContext addObject:item]; } @end
- 对外依然保持
NSArray的只读接口,完全隐藏内部的可变实现 - 内部语法简洁,直接用属性操作,不需要额外维护私有变量
- 符合Objective-C的标准封装实践
方案2:私有可变变量+返回不可变副本
如果需要确保外部拿到的数组绝对不可修改(哪怕强转成可变数组也只会修改副本),可以用私有可变数组存数据,重写公开属性的getter返回不可变副本:
// .m文件开头 @interface YourClass () { NSMutableArray<String *> *_mutableRouteContext; } @end @implementation YourClass - (instancetype)init { self = [super init]; if (self) { _mutableRouteContext = [NSMutableArray array]; } return self; } - (NSArray<String *> *)routeContext { return [_mutableRouteContext copy]; } // 内部操作私有变量 - (void)removeRouteItem:(NSString *)item { [_mutableRouteContext removeObject:item]; } @end
注意:这种方式每次访问routeContext都会生成新的副本,频繁调用会有轻微性能损耗,适合对数据不可变性要求极高的场景。
不推荐的方案:KVC操作私有存储
虽然可以通过KVC直接操作属性对应的私有变量,但这种方式破坏封装,代码可读性差,不建议使用:
// 示例(仅作反面参考) - (void)addItem:(NSString *)item { NSMutableArray *mutableArray = [self valueForKey:@"_routeContext"]; [mutableArray addObject:item]; }
关于为什么不暴露NSMutableArray属性
你提到的点非常准确:readonly修饰NSMutableArray毫无意义——外部拿到可变数组实例后,哪怕属性是只读的,依然可以直接调用addObject:、removeObject:等方法修改内部状态,彻底打破封装。所以对外暴露不可变数组是完全正确的设计。
内容的提问来源于stack exchange,提问作者Vlad Shlimovich
相关产品推荐
相关产品推荐

