對于剛入門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,保持接口文件的可閱讀性。