当你想从字典里删两项,却发现自己无处下手,这篇文章就是救命卡片。
背景场景
在某 iOS 项目 中,我们用字典字面量为资料页配置「section → model class」映射:
NSDictionary<NSString *, Class> *sectionModelBuilderMap = @{
SectionNameVerification : VerificationSectionModel.class,
...
SectionNameAboutMe : AboutMeSectionModel.class,
...
SectionNameQa : QASectionModel.class,
};
现在产品决定 暂时下线 AboutMe 和 Qa。问题来了:
能否直接把这两项从现有字典里“抠”掉?
为什么无法“原地删除”
| 误区 | 真相 |
|---|---|
给 NSDictionary 调 removeObjectForKey: |
崩溃——字面量生成的是不可变对象 |
在分类里给 self 重新赋值(self = xxx) |
编译不过——self 是只读指针 |
想在分类内部 self = [m copy] |
行不通,见下文「不能给 self 赋值」 |
self 不能重新指向新对象
在 实例方法 和 分类方法 中,编译器把 self 视为 const struct objc_object *const self:
前一个 const:self 指向的对象内容在方法体内可变(你可以调对象的普通 setter)。
后一个 const:指针本身不可变,所以 self = [m copy] 直接编译错误:
“Cannot assign to variable ‘self’”。
更重要的是,就算能改 self,外部变量(sectionModelBuilderMap)依旧指向旧对象,需求也满足不了。
社区惯例:拷贝-修改-再拷贝
sectionModelBuilderMap =
[sectionModelBuilderMap dictByRemovingKeys:@[
SectionNameAboutMe,
SectionNameQa
]];
分类实现:
@implementation NSDictionary (DictFilter)
- (NSDictionary *)dictByRemovingKeys:(NSArray<id<NSCopying>> *)keys {
if (keys.count == 0) return self; // 无需处理
NSMutableDictionary *m = [self mutableCopy]; // ① 可变副本
[m removeObjectsForKeys:keys]; // ② 就地删键
return [m copy]; // ③ 再拷回不可变
}
@end
线程安全:外部仍拿到不可变对象。
调用简洁:一行搞定过滤。
崩溃零风险:所有修改都在可变副本上完成。
如果你执意内部替换指针
void RemoveKeysFromDict(NSArray *keys,
NSDictionary *__strong *dictPtr) {
NSMutableDictionary *m = [*dictPtr mutableCopy];
[m removeObjectsForKeys:keys];
*dictPtr = [m copy]; // 改变调用方指针
}
RemoveKeysFromDict(@[SectionNameAboutMe, SectionNameQa], §ionModelBuilderMap);
Objective-C 很少这样写,可读性差,调 API 同样两行,不如直接返回新对象。
TL;DR
字面量 NSDictionary 不可变,直接删键会崩。
方法体里 self 指针不可重新赋值,self = [m copy] 编译不过。
最佳实践:mutableCopy → removeObjectsForKeys → copy,再把新字典重新赋给原变量。
想更优雅?封装成分类,让调用方只管传「要删的键」,代码易读又安全。
“Mutable when you need it, immutable when you can.” — Apple Collection Programming Guide
















暂无评论内容