標籤:objective-c 屬性 成員變數 類
在Objective-C的類與對象的概念中. 成員變數與屬性的區別與聯絡一直沒有搞清楚. 直到學習了慕課網上的這個課程Objective-C物件導向初體驗, 才算真正有了點感覺了. 最關鍵的結論就是: 類內使用成員變數{}, 類外使用屬性@property.
成員變數成員變數及其get方法.
首先, 我們來看下基本的類成員變數及其使用.
// People.h@interface People : NSObject{ NSString *_peopleName;}@end
在.m中不做任何事情, 然後在main.m調用_peopleName成員變數,
(可以看出, 調用類的成員變數時, 使用 . 文法符號會出錯, 必須使用->來調用):
調用類成員變數" title="">
改為->, 調用p1->_peopleName的結果如下:
即, 該_peopleName預設是protected, 外部調用需要設定為@public. 改動一下:
// People.h@interface People : NSObject{ @public NSString *_peopleName;}@end
調用p1->_peopleName的結果如下:
2015-05-06 15:58:41.039 memberAndProperty[2851:304100] p1._peopleName : (null)
類內部使用成員變數
如果想在init中初始化_peopleName, 則在People.m中:
// People.m- (instancetype)init{ self = [super init]; if (self) { _peopleName = @"people name 1"; } return self;}
調用p1->_peopleName的結果如下:
2015-05-06 16:01:36.974 memberAndProperty[2895:306281] p1._peopleName : people name 1
其他使用該成員變數的類內部方法都是類似的用法.
set方法
以上是對類成員變數_peopleName的調用, 如果想要對其附新值呢?
// main.m People *p1 = [[People alloc] init]; NSLog(@"p1._peopleName : %@", p1->_peopleName); p1->_peopleName = @"people name 2"; NSLog(@"p1._peopleName : %@", p1->_peopleName);
結果:
2015-05-06 16:05:34.915 memberAndProperty[2931:309406] p1._peopleName : people name 12015-05-06 16:05:34.916 memberAndProperty[2931:309406] p1._peopleName : people name 2
以上可見, 將_peopleName設定為@public之後, 可在類外對其進行get/set操作, 直接調用或賦值即可.
但不推薦使用p1->_peopleName這樣的形式. 因為, 這樣就不符合我們所說的
“類內使用成員變數{}, 類外使用屬性@property“的結論了. 且將成員變數_peopleName設為@public會很不安全.
自訂成員變數的get/set方法
仍然將成員變數_peopleName預設為@protected, 從類內部的方法中對_peopleName進行讀取或賦值, 然後間接傳遞至類外部, 是一個不錯的選擇.
首先, 在.h中聲明getName和setName方法:
// People.h@interface People : NSObject{ NSString *_peopleName;}-(NSString *)getName;-(void)setName:(NSString *)name;@end
在.m中, get/set這兩個方法是以在類內部對成員變數_peopleName進行調用或賦值的方式來實現的.
// People.m-(NSString *)getName { return _peopleName;}-(void)setName:(NSString *)name { _peopleName = name;}
那麼, 調用的時候就非常方便了:
// main.m People *p1 = [[People alloc] init]; NSLog(@"p1.getName : %@", p1.getName); [p1 setName:@"people name 2"]; NSLog(@"p1.getName : %@", p1.getName);
結果如下:
2015-05-06 16:25:36.019 memberAndProperty[3036:320317] p1.getName : people name 12015-05-06 16:25:36.020 memberAndProperty[3036:320317] p1.getName : people name 2
使用自訂的get/set, 從類內部調用成員變數是一種比較常見的方式. 但需手動添加這兩個方法.
屬性
那麼, 有沒有更加簡便的方法呢? 或者說, get/set這種非常常見的操作, 能不能預設提供給我們呢? 答案是肯定的!
在新的iOS SDK中, 使用@property來定義類的屬性, 是專用於從類外部對其進行調用或賦值的.
在.h中先聲明peopleName屬性:
// People.h@interface People : NSObject{ NSString *_peopleName;}@property(nonatomic, strong) NSString *peopleName;// nonatomic 非原子性訪問, 不加同步機制, 多線程並非訪問時可提高效能// strong 相當於一個深拷貝的操作@end
在.m中使用@synthesize指令將peopleName屬性與_peopleName成員變數關聯起來:
// People.m@implementation People@synthesize peopleName = _peopleName;- (instancetype)init{ self = [super init]; if (self) { _peopleName = @"people name 1"; } return self;}@end
即, 編譯器遇到@synthesize peopleName = _peopleName;時, 會自動產生對peopleName的get/set方法.
且這裡的底線_是必不可少的, 否則就不能正確地將屬性與成員變數關聯起來.
然後, 我們直接調用即可:
// main.m People *p1 = [[People alloc] init]; NSLog(@"p1.peopleName : %@", p1.peopleName); p1.peopleName = @"people name 2"; NSLog(@"p1.peopleName : %@", p1.peopleName);
結果如下:
2015-05-06 16:32:29.142 memberAndProperty[3094:325295] p1.peopleName : people name 12015-05-06 16:32:29.143 memberAndProperty[3094:325295] p1.peopleName : people name 2
實際上, 編譯器比我們想象中更聰明, 在.h檔案中的{ NSString *_peopleName; }這個成員變數不需要聲明也可以. 僅僅聲明了@property(nonatomic, strong) NSString *peopleName;這個屬性, xcode也會預設自動為我們聲明一個該類的peopleName成員變數, 及隱藏的get/set方法. 這裡, 就體現出了底線 的作用了.
結論
結論依然是: 類內使用成員變數{}, 類外使用屬性@property.
因此在類外的話, 強烈推薦使用屬性@property.
而如果非要在類外使用成員變數{}, 則要麼將該成員變數設為@public, 要麼自訂其get/set方法, 利用這兩個方法從類內部對成員變數進行調用或賦值. 這兩種方法各自的弊端及使用請參考以上內容.
Objective-C中類的成員變數與屬性