对于刚入门OC开发的人都有一个疑惑,就是下面这些方式创建实例变量有什么区别呢?PS:为了简化,这里省略了property的修饰词。
@interface Person : NSObject {
@public int a;
@protected int b;
@private int c;
}
@property int d;
2,3,4行创建的是实例变量,或成员变量。对C还有印象的都知道结构体吧,OC的类本质上就是一个结构体。
第7行声明的是一个property,直译为属性。它与实例变量是有区别的。
-
面向对象的封特性
存取一个对象的成员变量时,我们应该使用setter和getter方法,而不是直接引用对象的成员变量。
@interface SomeClass : NSObject
- (void)setName:(NSString *)name;
- (NSString *)name;
@end
@implementation SomeClass {
NSString *_privateName;
}
- (void)setName:(NSString *)name {
self->_privateName = name;
}
- (NSString *)name {
return self->_privateName;
}
@end
这是一个简单的类,该类有一个私有的_privateName
实例变量写在@implementation
里面,这个实例变量只能在内部使用,外部无法引用。为了让外部能存取这个实例变量,@interface
里分别写了getter和setter方法,外部通过这两个方法来访问对象的实例变量。这是一种基本的面向对象设计方式。
但是每次添加一个实例变量都要为它们创建对应的setter和getter,无疑会添加大量的工作量,所以苹果工程师在后续的xcode里添加一些语法支持来降低输入量,这就是property的作用。
@interface SomeClass : NSObject
@property NSString *name;
@end
@implementation SomeClass
@end
可以看到的是,这里一行就可以搞定了。简单来说声明一个property为我们省下了自行添加实例变量和添加setter和getter的时间。值得注意的是,添加property后,系统会自动生成对应的实例变量,该实例变量的名字是property名字前加下划线,如_name
与property相关的是点语法。
SomeClass *a = [SomeClass new];
a.name = @"just a";
NSString *name = a.name;
点语法并不如外表那样看上去那么简单,它可以被展开的。
[a setName:@"just a"];
NSString *name = [a name];
这两个方法是不是很熟识了?上面已经说过了,是setter和getter,点语法是将它们简化了。
-
实例变量的访问控制
上面的例子里提到在@implementation
里声明的实例变量是只能在内部访问的,是私有的。另外这种声明是不能被子类引用的。
实例变量有三种常见的访问修饰词
- @public, 这个声明的实例变量可以在任何地方访问。
- @protected,系统默认的,当没有指定时会默认这个。不能被外部访问,但能被子类访问。
- @private,完全私有,这个就等同与声明在
@implementation
里。
很久很久以前,程序员都习惯在@interface
里声明所有实例变量,并为其添加访问控制。那时到底基于什么原因这样写呢?我也搞不清楚,因为太远了。
对于现在来说,好的习惯是在类的@interface
里声明必要的property,保持接口文件的可阅读性。