OC MRC 成員變數, property, synthesize, dynamic
iOS @property、@synthesize和@dynamic
MRC 環境下: 建立一個 Person 類, 有 name, age, gender, weight 屬性:
最早的寫法: 成員變數
.h 檔案 @interface Person : NSObject //成員變數, 按蘋果程式碼規範要帶下劃線, 以便和 setter, getter 方法的引數區分 { NSString *_name; NSString *_gender; NSInteger _age; CGFloat _weight; } //宣告 setter, getter 方法 - (void)setName:(NSString *)name; - (NSString *)name; - (void)setGender:(NSString *)gender; - (NSString *)gender; - (void)setAge:(NSInteger)age; - (NSInteger)age; - (void)setWeight:(CGFloat)weight; - (CGFloat)weight; @end
.m 檔案 @implementation Person //實現 setter, getter 方法 - (void)setName:(NSString *)name { _name = name; } - (NSString *)name { return _name; } - (void)setGender:(NSString *)gender { _gender = gender; } - (NSString *)gender { return _gender; } - (void)setAge:(NSInteger)age { _age = age; } - (NSInteger)age { return _age; } - (void)setWeight:(CGFloat)weight { _weight = weight; } - (CGFloat)weight { return _weight; } @end
Xcode 4.4 之前的寫法: property 和 synthesize 共用
Xcode4.4版本之前: @property 和 @synthesize的功能是獨立分工的
- @property的作用是: 生成成員變數 set/get 方法的宣告
@property int age; 它的作用和下面兩行程式碼的作用一致
- (void)setAge:(int)age;
- (int)age;
//注意:屬性名稱不要加字首_ 否則生成的get/set方法中也會有下劃線
//屬性中帶有下劃線 _ 那麼生成的get/set也會有下劃線 _
//@property int _age;
//- (void)set_age:(int)_age;
//- (int)_age;
- @synthesize的作用
//@synthesize age//實現 @property 宣告的 set/get 方法, 生成私有的成員變數 age(不帶下劃線)
生成帶下劃線的成員變數:
@synthesize age = _age//實現 @property 宣告的 set/get 方法, 生成私有的成員變數 _age
//如果在.h檔案中沒有定義 _age 成員變數的話,就會在.m檔案中自動生成@private型別的成員變數_age
.h 檔案
@interface Person : NSObject
@property (nonatomic, assign) NSString *name;//相當於擁有了以下兩個方法的宣告
//- (void)setName:(NSString *)name;
//- (NSString *)name;
@property NSString *gender;//相當於擁有了以下兩個方法的宣告
//- (void)setGender:(NSString *)gender;
//- (NSString *)gender;
@property NSInteger age;//相當於擁有了以下兩個方法的宣告
//- (void)setAge:(NSInteger)age;
//- (NSInteger)age;
@property CGFloat weight;//相當於擁有了以下兩個方法的宣告
//- (void)setWeight:(CGFloat)weight;
//- (CGFloat)weight;
@end
.m 檔案
@implementation Person
@synthesize name = _name, gender = _gender, age = _age, weight = _weight;
或分開寫:
@synthesize name = _name;//相當於以下兩個方法
//- (void)setName:(NSString *)name {
// _name = name;
//}
//- (NSString *)name {
// return _name;
//}
@synthesize gender = _gender;//相當於以下兩個方法
//- (void)setGender:(NSString *)gender {
// _gender = gender;
//}
//- (NSString *)gender {
// return _gender;
//}
@synthesize age = _age;//相當於以下兩個方法
//- (void)setAge:(NSInteger)age {
// _age = age;
//}
//- (NSInteger)age {
// return _age;
//}
@synthesize weight = _weight;//相當於以下兩個方法
//- (void)setWeight:(CGFloat)weight {
// _weight = weight;
//}
//- (CGFloat)weight {
// return _weight;
//}
@end
Xcode4.4之後: @property 代替了 @synthesize的功能
@property 的作用:
- 生成了成員變數 get/set 方法的宣告
- 生成了私有的帶下劃線的的成員變數因此子類不可以直接訪問,但是可以通過get/set方法訪問。那麼如果想讓定義的成員變數讓子類直接訪問那麼只能在.h檔案中定義成員變量了,因為它預設是@protected
- 生成了get/set方法的實現
注意:
- 當讓系統自動生成setter 以及 getter 方法實現時,此時系統會自動生成例項變數
- 如果我們自己重寫了setter 和 getter 方法其中之一時,系統還會自動生成例項變數
- 如果我們自己重寫了setter 和 getter ,那麼此時系統不再自動生成例項變數,需要我們自己建立例項變數,或者使用@sythesize來生成例項變數, 此時的例項變數是私有的
//@sythesize 在.m檔案中的作用:
//(1)生成setter 和 getter 方法的實現
//(2)生成內部操作的例項變數
.h 檔案
@interface Person : NSObject
@property (nonatomic, retain) NSString *name;
@property (nonatomic, copy) NSString *gender;
@property (nonatomic, assign) NSInteger age;
@property (nonatomic, assign) CGFloat weight;
@end
注意: 當使用屬性時, 為了防止記憶體洩露, 不同語義特性 retain, copy, assign 修飾的屬性, 其 setter , getter 的內部實現有所不同
注意retain, copy 修飾的屬性的 setter, getter 方法的實現
#pragma mark --- 不同語義特性下的setter 和getter 的內部實現
#if 0
//assign,系統預設
//setter 方法
- (void)setName:(NSString *)name {
_name = name;
}
//getter 方法
- (NSString *)name {
return _name;
}
#endif
#if 0
//retain
//setter 方法
- (void)setName:(NSString *)name {
if (_name != name) {//避免重複操作
[_name release];//解決記憶體洩露問題
_name = [name retain];//解決野指標問題
}
}
//getter 方法
- (NSString *)name {
return [[_name retain] autorelease];//蘋果推薦的getter方法的安全處理機制
}
#endif
#if 0
//copy
//setter 方法
- (void)setName:(NSString *)name {
if (_name != name) {
[_name release];
_name = [name copy];
}
}
//getter
- (NSString *)name {
return [[_name retain] autorelease];
}
#endif
@dynamic
@dynamic 告訴編譯器:屬性的 setter 與 getter 方法由使用者自己實現,不自動生成。假如一個屬性被宣告為 @dynamic var,而且你沒有提供 @setter方法和 @getter 方法,編譯的時候沒問題,但是當程式執行到 instance.var = someVar,由於缺 setter 方法會導致程式崩潰;或者當執行到 someVar = var 時,由於缺 getter 方法同樣會導致崩潰。編譯時沒問題,執行時才執行相應的方法,這就是所謂的動態繫結。