前言
经常开发的过程中在类中定义成员变量,声明成员变量的时候,发现可以在变量前面加上@private,@protected,@public,@package。他们之间有啥区别么?下面就说一下。
一、@private
代表私有,也就是只有自己有,别人谁都不可用,不可以继承的。
让我们用代码实践一下,如下定义一个Person.h
@interface Person : NSObject {
@private
NSString *_priName;
}
@end
在Person.m代码如下:
@implementation Person
- (instancetype)init {
self = [super init];
if (self) {
//类内部可以调用
self->_priName = @"私有变量";
}
return self;
}
@end
在类外调用这个方法:
Person *person = [[Person alloc] init];
//会报Instance variable '_priName' is private这个错误
person->_priName = @"私有变量";
在类的外部,也无法访问私有变量。
在继承于Person的Student中
@implementation Student
- (instancetype)init {
self = [super init];
if (self) {
//Instance variable '_priName' is private 编译的时候报错
self->_priName = @"ahaha";
}
return self;
}
说明继承Person的Student也访问不了父类私有变量。
使用@private声明的变量 :
- @private变量只能在类内部调用,在类外无法访问
- 继承该类的子类也无法访问
二、@protected 受保护的
相较上边的private而言,就没有那么自私了,它自己可以用,自己的子类也是可以共享的,是可以继承的.
在Person.h添加@protected类型的变量
@protected
NSString *_proName;
在Student.m初始化init里给这个_proName赋值
@implementation Student
- (instancetype)init {
self = [super init];
if (self) {
// self->_priName = @"ahaha";
//没有报错,所以子类能访问
self->_proName = @"受保护变量";
}
return self;
}
@end
没有报错,所以子类能访问。
Person *person = [[Person alloc] init];
//编译报异常,Instance variable '_proName' is protected
person->_proName = @"aaa";
说明在类外面也不能调用@protected声明的变量
@implementation Person
- (instancetype)init {
self = [super init];
if (self) {
//类内部可以调用
self->_proNmae = @"受保护变量";
}
return self;
}
@end
在类的内部是可以调用的
- @potected可以访问的权限比private大
- 在类外面不能调用potected变量
- 在类里或者继承该类的子类里可以使用该变量
三、@protected 公开的
相较上边而言,谁都可以用,只要你有这个类的对象,就可以拿到public下的变量。
在Person.m文件里
//没报错
self->_proNmae = @"公开的变量";
可以在类实例里面调用
在Student.m文件里
//没报错
_proNmae = @"公开的变量";
在该类的子类Student实例内也可以调用
//没报错
self->_proNmae = @"公开的变量";
可以在该类子类实例里面调用
//无编译异常
Person *person = [[Person alloc] init];
person->_pubName = @"父类公开变量";
//无编译异常
Student *stu = [[Student alloc] init];
stu->_pubName = @"子类公开变量";
说明子类和父类在类外面可以访问@public变量
- 该类实例内,还是在外面调用都可以
- 继承的子类的实例内或者在外面调用改实例都可以获取该变量
四、@package 框架的
这个主要是用于框架类,使用@private太限制,使用@protected或者@public又太开放,就使用这个package吧。
你可以使用pods引入一个第三方框架,然后在改变第三框架的源码,可以在类中加上
@package
NSString *_pacName;
然后在框架外声明实例并且访问这个变量
//修改的对象例如PFObject
PFObject *object = [[PFObject alloc] init];
//这里不会报错提示,运行时候会报错
object->_pacName = @"框架外赋值";
运行时报错:
Undefined symbols for architecture x86_64:
"_OBJC_IVAR_$_DTAttributedLabel._pacName", referenced from:
-[ViewController viewDidLoad] in ViewController.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
- 对于framework内部,相当于@public
- 对于framework外部,相当于@private
这个特性,很适合用于开发第三方的静态类库,因为多数人并不希望让别人知道自己属性的值。