如何在Objective-C的Work类中防止修改传入的UserSettings实例属性?
解决OC中限制类内对外部对象属性修改的问题
这个场景我太熟悉了——你想让Work类持有UserSettings但只能读不能改,之前用readonly和const没效果,核心原因是这俩都没限制到UserSettings对象自身的属性读写权限,只是限制了Work类里的指针或属性赋值。下面给你两个靠谱的解决方案,都能触发编译错误,从根源上阻止修改操作:
方案一:用只读协议约束接口
这是最通用的做法,适合多个类都需要只读访问UserSettings的场景:
- 先定义一个只包含只读属性的协议:
// UserSettingsReadOnly.h @protocol UserSettingsReadOnly <NSObject> @property (nonatomic, readonly, copy) NSString *color; // 把UserSettings里所有需要暴露给Work的属性都以readonly声明在这里 @end
- 让你的UserSettings类遵守这个协议:
// UserSettings.h #import "UserSettingsReadOnly.h" @interface UserSettings : NSObject <UserSettingsReadOnly> // 这里保留原有的readwrite属性,外部依然可以正常修改 @property (nonatomic, copy) NSString *color; // 其他读写属性... @end
- 在Work类里用协议类型来持有settings:
// Work.m @interface Work() @property (nonatomic, strong) id<UserSettingsReadOnly> settings; @end @implementation Work - (instancetype)initWithSettings:(UserSettings *)settings { if (self = [super init]) { _settings = settings; // 尝试修改会直接触发编译错误:Property 'color' is readonly // self.settings.color = @"red"; } return self; } @end
原理:编译器在Work类里只会识别UserSettingsReadOnly协议里的只读属性,所以任何修改属性的操作都会被拦截,而外部给Work传UserSettings对象完全没问题,因为它遵守了协议。
方案二:用私有类别缩小可见范围
如果只有Work类需要这个限制,不想多写一个协议文件,可以在Work的实现文件里给UserSettings加一个私有类别:
// Work.m // 私有类别,只在当前文件生效 @interface UserSettings (ReadOnlyForWork) @property (nonatomic, readonly, copy) NSString *color; @end @interface Work() @property (nonatomic, strong) UserSettings *settings; @end @implementation Work - (instancetype)initWithSettings:(UserSettings *)settings { if (self = [super init]) { _settings = settings; // 同样会触发编译错误:Property 'color' is readonly // self.settings.color = @"red"; } return self; } @end
原理:这个私有类别会覆盖Work类对UserSettings属性的认知,编译器认为color是只读的,自然不允许修改。外部代码不受任何影响,因为这个类别只在Work.m里可见。
为什么之前的方法没用?
@property(readonly) UserSettings * settings;:这个只是限制了Work类不能重新赋值settings指针(比如不能写self.settings = newSettings),但UserSettings对象本身的color属性还是readwrite的,所以修改依然可行。const UserSettings * _settings;:OC里的const是指针常量,意思是不能修改_settings指向的地址,但指针指向的对象的属性依然可以修改——OC没有像C++那样的对象级const约束,所以这个方法无效。
内容的提问来源于stack exchange,提问作者Heefan
相关产品推荐
相关产品推荐

