我們先來說說@property和@synthesize @property宣告成員變數,會自動幫我們生成該成員變數的getter/setter方法的宣告; @synthesize的作用是自動生成成員變數的getter/setter方法的定義; 所有被宣告為屬性的成員,在iOS5 之前需要使用編譯器指令@synthesize 來告訴編譯器幫助生成屬性的getter,setter方法。之後這個指令可以不用人為指定了,預設情況下編譯器會幫我們生成。 這裡先淺顯的說明@property和synthesize的作用,其他的知識自己google,今天主要回顧self.a和_a的區別。
首先使用self.a會呼叫getter/setter方法,而_a並不會呼叫getter/setter方法,它是直接訪問例項變數並賦值。 下面我們通過@property的copy屬性舉例說明:
#import <Foundation/Foundation.h>
@interface Person : NSObject
@property (nonatomic, copy) NSString *name;
@property (nonatomic, copy) NSString *sex;
- (void)changeNameValue:(NSString *)newName andChangeSexValue:(NSString *)sexValue;
@end
複製程式碼
上面是一個Person類,裡面有兩個成員變數name和sex,宣告瞭一個例項方法changeNameValue:andChangeSexValue:,下面例項方法的實現:
#import "Person.h"
@implementation Person
- (void)changeNameValue:(NSString *)newName andChangeSexValue:(NSString *)sexValue
{
self.name = newName;
_sex = sexValue;
}
@end
複製程式碼
然後在viewDidLoad方法中呼叫:
- (void)viewDidLoad {
[super viewDidLoad];
NSMutableString *newName =[NSMutableString stringWithString:@"TongRy"];
NSMutableString *newSex = [NSMutableString stringWithString:@"man"];
Person *xiaoming = [[Person alloc] init];
[xiaoming changeNameValue:newName andChangeSexValue:newSex];
NSLog(@"xiaoming newName: %@, newSex: %@;", xiaoming.name, xiaoming.sex);
[newName appendString:@"Good"];
[newSex appendString:@"andwoman"];
NSLog(@"To observe the changes : xiaoming name: %@, sex: %@;", xiaoming.name, xiaoming.sex);
}
複製程式碼
執行後得到的結果:
我們可以看到,newName和newSex改變了,name的值仍然沒有變是TongRy,而sex的值確是改變了,末尾增加了“andwoman”.實際上我們期待的是對類屬性的賦值是深拷貝賦值(我們宣告瞭@property的copy屬性),但是實際得到的結果是name進行了深拷貝,而sex仍然是淺拷貝。究其原因,就是因為name是self訪問,sex是_訪問。在呼叫self的時候,如果是賦值,那麼編譯器會自動根據strong/copy生成對應的setter方法,其實現類似於:
//宣告為copy屬性時
- (void)setName:(NSString *)name
{
if (_name != name)
{
[_name release];
_name = [name copy];
}
}
//當宣告為retain屬性時(MRC下)
- (void)setName:(NSString *)name
{
if (_name != name)
{
[_name release];
[name retain];
_name = name;
}
}
複製程式碼
在上面的例子中,使用self.name賦值後,name已經和newName沒有指向同一塊記憶體,所以name沒有隨著newName值的改變而改變。_sex賦值是直接指向了newSex所指向的記憶體塊,也沒有做retain操作,容易出現問題。所以,我們在類中應該儘量使用self.a的形式來訪問屬性。
用self.name 是更好的選擇,因為這樣可以相容懶載入,同時也避免了使用下劃線的時候忽視了self這個指標,後者容易在block中造成迴圈引用。同時,使用_是獲取不到父類的屬性,因為它只是對區域性變數的訪問。