IOS中实例的权限控制
- @public、@protected、@private的使用
在OC中声明一个类的时候,可以使用上面 @public、@protected、@private三个关键字声明实例的权限,例如下面的代码:
#import <Foundation/Foundation.h> @interface Person : NSObject { @public NSString *_height; @protected NSString *_weight; @private NSString *_wife; } @end @interface Person () { @public NSString *_name; @protected NSString *_sex; @private NSString *_phoneNO; } - (void)publicMethod; @end @implementation Person - (instancetype)init { if(self = [super init]) { _height = @"1.8m"; _weight = @"65Kg"; _wife = @"none"; _name = @"zhangSan"; _sex = @"man"; _phoneNO = @"1122334455"; } return self; } - (void)publicMethod { } @end
在.h文件中定义了三个实例,这三个实例的权限和public、protected、private相对应,对于一个Person类型的对象p,_name在任何地方都是可以访问的,_sex只能在Person
的子类中访问,_wife只能自己内部访问。在.m文件中定义的三个实例也与public、protected、private相对应,需要注意的是,在其它文件中定义的Person类型的对象p,都不能访问到这三个实例,只有在.m文件内部,public、protected、private才会起到对应的作用。实际上OC中实例的权限控制只是编译时的一种权限限制,在OC runtime的类结构中,实例变量是不存在权限控制的,同样类方法、实例方法也不存在权限控制。
- 对于KVC来说,无论实例是哪种权限都是可以轻松访问到的,如下面的代码:
-
@interface Student : Person @end @implementation Student + (void)testProtected { Person *p = [Person new]; NSLog(@"%@",p->_height); NSLog(@"%@",p->_weight); } - (NSString *)description { Person *p = [Person new]; NSLog(@"%@",p->_height); NSLog(@"%@",p->_weight); // NSLog(@"%@",p->_wife); // [p publicMethod]; // [self publicMethod]; //return [NSString stringWithFormat:@"name == %@\nsex == %@\nphone == %@",_name, _sex,_phoneNO] // return [NSString stringWithFormat:@"name == %@\nsex == %@",_name, _sex]; // return [NSString stringWithFormat:@"%@ , %@ , %@",_height , _weight ,_wife]; return [NSString stringWithFormat:@"%@ , %@",_height , _weight]; } @end
KVC访问:
-
#import "Other.h" #import "Person.h" @interface Other : NSObject - (void)testProtected; - (void)testKVC; @end @implementation Other - (void)testProtected { Person *p = [Person new]; NSLog(@"%@",p->_height); // NSLog(@"%@",p->_weight); } - (void)testKVC { Person *p = [Person new]; NSLog(@"%@",[p valueForKey:@"_name"]); NSLog(@"%@",[p valueForKey:@"_sex"]); NSLog(@"%@",[p valueForKey:@"_phoneNO"]); NSLog(@"%@",[p valueForKey:@"_wife"]); } @end
实际KVC读取一个实例变量:
-
- (id)valueForKey: (NSString*)key { if (!key) { id value = [self valueForUndefinedKey:nil]; return value; } const char *keyCString = [key UTF8String]; SEL sel = sel_getUid(keyCString); // FIXME: getKey, _getKey, isKey, _isKey are missing if ([self respondsToSelector:sel]) { id value = [self _wrapReturnValueForSelector:sel]; return value; } size_t keyCStringLength = strlen(keyCString); char *selBuffer = __builtin_alloca(keyCStringLength + 5); char *keyname = __builtin_alloca(keyCStringLength + 1); strcpy(keyname, keyCString); #define TRY_FORMAT(format)\ sprintf(selBuffer, format, keyname);\ sel = sel_getUid(selBuffer);\ if ([self respondsToSelector:sel]) {\ id value = [self _wrapReturnValueForSelector:sel];\ return value;\ } TRY_FORMAT("_%s"); keyname[0] = toupper(keyname[0]); TRY_FORMAT("is%s"); TRY_FORMAT("_is%s"); // TRY_FORMAT("get%s"); // TRY_FORMAT("_get%s"); #undef TRY_FORMAT if ([isa accessInstanceVariablesDirectly]) { sprintf(selBuffer, "_%s", keyCString); sel = sel_getUid(selBuffer); if ([self respondsToSelector:sel]) { id value = [self _wrapReturnValueForSelector:sel]; return value; } Ivar ivar = class_getInstanceVariable(isa, selBuffer); if (!ivar) { ivar = class_getInstanceVariable(isa, keyCString); } if (ivar) { id value = [self _wrapValue:(void*)self + ivar_getOffset(ivar) ofType:ivar_getTypeEncoding(ivar)]; return value; } } id value = [self valueForUndefinedKey:key]; return value; }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 提示词工程——AI应用必不可少的技术
· Open-Sora 2.0 重磅开源!
· 周边上新:园子的第一款马克杯温暖上架