正确理解私有、保护和公有
在OC中属性默认都是公有的。如果有私有、保护和公有成员的需求,也可以通过OC关键字进行设置。
The Scope of Instance Variables
To enforce the ability of an object to hide its data, the compiler limits the scope of instance variables—that is, limits their visibility within the program.
But to provide flexibility, it also lets you explicitly set the scope at four levels. Each level is marked by a compiler directive:
Directive | Meaning |
---|---|
@private | The instance variable is accessible only within the class that declares it. |
@protected | The instance variable is accessible within the class that declares it and within classes that inherit it. All instance variables without an explicit scope directive have @protected scope. |
@public | The instance variable is accessible everywhere. |
@package | Using the modern runtime, an @package instance variable has @public scope inside the executable image that implements the class, but acts like @private outside.The @package scope for Objective-C instance variables is analogous to private_extern for C variables and functions. Any code outside the class implementation’s image that tries to use the instance variable gets a link error.This scope is most useful for instance variables in framework classes,where @private may be too restrictive but @protected or @public too permissive. |
通过上面文档,可以总结出在实例变量被直接操作的情况下,有以下可见性指令:
- @public:实例变量可使用符号 person->age = 32”被直接读取。
- @package:实例变量是公开的,除非它被指定在框架外(仅适用64位架构)
- @protected:实例变量仅可由其类和其衍生类访问
- @private:实例变量仅可由其类访问
对于@package,在stackoverflow上有一个很好的解释:
- @package is similar to internal for .NET. It means the member is accessible only from the framework in which it is defined.
- Note: In 32-bit it acts like @public.
package 解释
OC中定义私有变量的方法
在.h中定义私有变量:
@interface Father : NSObject { @private NSInteger privateVar; } @end
通过Extension来定义私有变量
@interface Father () @property (nonatomic, strong) NSString *song; @end
在implement中定义 私有变量
@implementation Father { NSInteger fAbc; NSString *abcString; } @end
private、protected、public对比
@interface Father : NSObject {
@private
NSInteger privateVar;
@protected
NSInteger protectedVar;
@public
NSInteger publicVar;
}
@end
在定义这些变量的类中可以访问私有的、保护的和公有的变量。而在它的子类中是不能访问私有变量的,只能访问保护的和公有的变量。
并且在实例化的对象中,只能访问公有变量,私有的和保护的变量均不能访问。
KVC方式访问变量
在父类中定义公有方法:
- (void)printPrivateVar
{
NSLog(@"privateVar:%ld", privateVar);
NSLog(@"protectedVar:%ld",protectedVar);
}
实例化对象通过KVC方式访问变量:
Father *father = [Father new];
[father setValue:@"123" forKey:@"privateVar"];
[father setValue:@"123456" forKey:@"protectedVar"];
[father printPrivateVar];
NSLog(@"father privateVar:%@", [father valueForKey:@"privateVar"]);
NSLog(@"father protectedVar:%@\n\n", [father valueForKey:@"protectedVar"]);
![Screen Shot 2016-08-03 at 22.22.57.png](http://upload-images.jianshu.io/upload_images/1171890-40e16cf17d85d768.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
Son *son = [Son new];
[son setValue:@"456789" forKey:@"privateVar"];
[son setValue:@"123456789" forKey:@"protectedVar"];
[son printPrivateVar];
NSLog(@"son privateVar:%@", [son valueForKey:@"privateVar"]);
NSLog(@"son protectedVar:%@", [son valueForKey:@"protectedVar"]);
打印结果如下:
extension和implement中定义的私有
Father类
//.h
@interface Father : NSObject {
@private
NSInteger abc;
}
@property (nonatomic, strong) NSString *songOne;
- (void)printVar;
@end
//.m
@interface Father () {
@private
int privateVar;
@protected
int protectedVar;
@public
int publicVar;
}
@property (nonatomic, strong) NSString *song;
@end
@implementation Father {
NSInteger fAbc;
}
- (void)printVar
{
NSLog(@"father abc:%@", [self valueForKey:@"abc"]);
NSLog(@"father song:%@", [self valueForKey:@"song"]);
NSLog(@"father songOne:%@", [self valueForKey:@"songOne"]);
NSLog(@"father privateVar:%@", [self valueForKey:@"privateVar"]);
NSLog(@"father protectedVar:%@", [self valueForKey:@"protectedVar"]);
NSLog(@"father publicVar:%@\n\n", [self valueForKey:@"publicVar"]);
NSLog(@"father fABC:%@", [self valueForKey:@"fAbc"]);
}
@end
son类
//.h
@interface Son : Father
- (void)printPrivate;
@end
//.m
@implementation Son
- (instancetype)init
{
if (self = [super init]) {
}
return self;
}
- (void)printPrivate
{
NSLog(@"son abc:%@", [self valueForKey:@"abc"]);
NSLog(@"son song:%@", [self valueForKey:@"song"]);
NSLog(@"son songOne:%@", [self valueForKey:@"songOne"]);
NSLog(@"son privateVar:%@", [self valueForKey:@"privateVar"]);
NSLog(@"son protectedVar:%@", [self valueForKey:@"protectedVar"]);
NSLog(@"son publicVar:%@", [self valueForKey:@"publicVar"]);
NSLog(@"son fABC:%@", [self valueForKey:@"fAbc"]);
}
@end
在实例化对象中通过KVC访问:
Father *father = [[Father alloc] init];
[father setValue:@"120" forKey:@"abc"];
[father setValue:@"123" forKey:@"songOne"];
[father setValue:@"456" forKey:@"song"];
[father setValue:@"12" forKey:@"privateVar"];
[father setValue:@"34" forKey:@"protectedVar"];
[father setValue:@"56" forKey:@"publicVar"];
[father setValue:@123456 forKey:@"fAbc"];
[father printVar];
Son *son = [Son new];
[son setValue:@"121" forKey:@"abc"];
[son setValue:@"1234" forKey:@"songOne"];
[son setValue:@"567" forKey:@"song"];
[son setValue:@"123" forKey:@"privateVar"];
[son setValue:@"456" forKey:@"protectedVar"];
[son setValue:@"789" forKey:@"publicVar"];
[son setValue:@1234567 forKey:@"fAbc"];
[son printPrivate];
打印结果
通过KVC的方式不管是私有的、保护的和公有的,都能进行访问。
得到当前类运行时的变量列表
unsigned int count = 0;
Ivar *members = class_copyIvarList([Father class], &count);
for (int i = 0 ; i < count; i++) {
Ivar var = members[i];
const char *memberName = ivar_getName(var);
const char *memberType = ivar_getTypeEncoding(var);
NSLog(@"%s----%s", memberName, memberType);
}
打印Father类中变量为: