【iOS】为什么 readonly NSMutableArray 还能被修改?——Objective-C 中的“只读”迷思

在日常 Objective-C 开发中,我们常常会给属性加上 readonly 修饰符,认为这样就能防止外部修改它。
但是很多同学第一次遇到下面的情况时,都会一脸疑惑:

@property (nonatomic, strong, readonly) NSMutableArray<FBMutableBeacon *> *beacons;

// 代码里竟然还能这么写
[self.beacons addObject:beacon];
[self.beacons removeObjectAtIndex:0];

不是 readonly 吗?为什么还能修改?
本文就来彻底解释这个问题。

 

1. readonly 的真正含义

在 Objective-C 中,readonly 的作用是 不生成 setter 方法,也就是说:

@property (nonatomic, strong, readonly) NSMutableArray *beacons;

等价于:

- (NSMutableArray *)beacons; // 只有 getter

因此你不能写:

self.beacons = [NSMutableArray array]; // ❌ 编译错误,没有 setter

这就是 readonly 的全部含义。
换句话说,它限制的是 重新赋值行为,而不是对象的修改。

 

2. 可变对象依然可变

再看一遍上面的例子:

[self.beacons addObject:@"BeaconA"];     // ✅ 合法
[self.beacons removeObjectAtIndex:0];   // ✅ 合法

原因很简单:

  • beacons 指向的是一个 NSMutableArray 对象。

  • NSMutableArray 本身就是可变的,提供了 addObject:removeObject: 等方法。

  • 调用这些方法修改的不是属性本身,而是数组内容。

所以,readonly 并不会阻止这种修改。

 

3. 常见误区

很多人会把 readonlyimmutable(不可变对象) 混为一谈。
实际上它们完全不同:

  • readonly:只读属性,不能重新赋值,但对象本身是否可变要看类型。

  • NSArray:不可变对象,本身就没有修改方法。

  • NSMutableArray:可变对象,依然可以修改。

对比一下:

@property (nonatomic, strong, readonly) NSMutableArray *arr1;
@property (nonatomic, strong, readonly) NSArray *arr2;

[arr1 addObject:@"A"]; // ✅ 合法
[arr2 addObject:@"A"]; // ❌ 编译错误,NSArray 没有这个方法

 

4. 正确的设计方式

如果你希望外部真正无法修改数组,有几种推荐做法:

✅ 方法一:用不可变类型暴露

@property (nonatomic, strong, readonly) NSArray<FBMutableBeacon *> *beacons;

内部依然可以用 NSMutableArray 存储,但对外只暴露 NSArray,自然无法修改。

 

✅ 方法二:返回副本(copy)

- (NSArray<FBMutableBeacon *> *)beacons {
    return [_beacons copy];  // 返回不可变拷贝
}

这样即使内部是可变数组,外部拿到的也是独立的不可变对象。

 

✅ 方法三:提供受控接口

而不是直接暴露数组,提供明确的方法:

- (void)addBeacon:(FBMutableBeacon *)beacon;
- (void)removeBeaconAtIndex:(NSUInteger)index;

这样可以完全控制外部对数据的修改方式。

 

5. 总结

  • readonly ≠ 不可变

  • 它只意味着属性不能被重新赋值,但并不保证对象本身不可变。

  • 想要真正防止外部修改数组内容,应该:

    1. 使用 NSArray 暴露

    2. 或者返回 copy

    3. 或者提供受控接口

一句话点题:
Objective-C 中的 readonly,其实只是“只读引用”,而不是“只读对象”。

 

👉 这就是 readonly NSMutableArray 还能被修改的根本原因。

 

posted @ 2025-08-25 14:09  码出境界  阅读(9)  评论(0)    收藏  举报