屬性 (Property)
不使用屬性的情況
@interface People : NSObject
{
NSString *firstName;
NSString *lastName;
double height;
double weight;
NSUInteger age;
NSString *company;
NSString *title;
NSString *address;
NSString *phone;
}
//類里定義了一些數(shù)據(jù)對(duì)應(yīng)的變量卒稳,既然類里有變量骆姐,想使用這個(gè)類码邻,就得定義這些變量相應(yīng)的讀取和設(shè)置的方法。
//對(duì)于類里某個(gè)變量的讀取和修改的方法稱作「訪問器」或「存取器」
- (void)setFirstName:(NSString*)name;
- (NSString)firstName;
- (void)setLastName:(NSString*)name;
- (NSString*)lastName;
- (void)setHeight:(double)h;
- (double)height;
…
@end
//這個(gè)類里有這么多變量何之,每個(gè)變量都需要聲明設(shè)置和讀取這么兩個(gè)方法躺彬。
//下面是方法的實(shí)現(xiàn)
@implementation People
- (void)setFirstName:(NSString)name {
firstName = name;
}
- (NSString*)firstName {
return firstName;
}
- (void)setLastName:(NSString)name {
lastName = name;
}
- (NSString*)lastName {
return lastName;
}
…
@end
//太多重復(fù)代碼了!
使用屬性的情況
@interface People : NSObject
@property NSString *firstName;
@property NSString *lastName;
@property double height;
@property double weight;
@property NSUInteger age;
@property NSString *company;
@property NSString * title;
@property NSString *address;
@property NSString *phone;
@end
@implementation People
@end
?
- 在使用
property
這個(gè)關(guān)鍵字聲明一條屬性的時(shí)候痢甘,OC為我們做的事如下:
property NSString *firstName; OC實(shí)際為我們完成的工作
NSString *_firstName;
- (void)setFirstName:(NSString *)firstName;
- (NSString *)firstName;
- (void)setFirstName:(NSString *)firstName {
…
}
- (NSString *)firstName {
…
}
//property為每個(gè)變量自動(dòng)定義了設(shè)置和讀取的方法
- 如何使用屬性?
|操作類型| 使用點(diǎn)號(hào)
|使用方法
|
|---|---|
|設(shè)置|people.firstName = @"First Name";|[people setFirstName:@"First Name"];
|讀取|NSString *firstName = people.firstName;|NSString *firstName = [people firstName];
屬性的聲明部分
@property (getter = getName, setter = setName:, readwrite, readonly, atomic, nonatomic, copy) NSString *name;
//包含三部分茉贡,屬性特質(zhì)产阱,屬性類型,屬性名稱
- 屬性的特質(zhì)
getter 和 setter
getter = getName
setter = setName:
//getter 和 setter 是為了方便我們自己給設(shè)置和訪問方法起名字
//這個(gè)例子里块仆,getName 和 setName本來就是默認(rèn)构蹬,但是我們可以換成我們自己想要的
readwrite 和 readonly
@interface People : NSObject
@property NSString *firstName;
@property NSString *lastName;
@property (readonly) NSString *fullName;
@end
//屬性fullName的特質(zhì)是readonly的王暗,就只可讀,不可修改
//fullName不是一個(gè)真正的變量庄敛,它是根據(jù)firstName和lastName拼接而成
//所以我們自己去定義這個(gè)屬性的讀取方法
- (NSString *)fullName {
return [NSString stringWithFormat:@"%@ %@", self.firstName, self.lastName];
}
atomic 和 nonatomic
//因?yàn)橛袝r(shí)要處理多線程并發(fā)的問題俗壹。OC默認(rèn)的屬性特制是atomic,
//當(dāng)我們?cè)诙鄠€(gè)線程同時(shí)訪問一個(gè)屬性的情況下藻烤,
//至少能保證我們這個(gè)屬性讀取到的是完整的绷雏。
//保證線程安全是需要性能開銷的,
//而我們的程序需要處理多線程的情況并不多怖亭,
//很多時(shí)候我們并不需要這個(gè)線程安全特性涎显。
//所以可以使用nonatomic這個(gè)特質(zhì),
//告訴OC我們這個(gè)屬性它不需要處理多線程并發(fā)的問題兴猩,
// 不要額外的增加線程安全的保證了期吓,
//這樣可以提高我們屬性的讀取和寫入的效率。
@property (readonly, nonatomic) NSString *fullName;
一些跟內(nèi)存管理相關(guān)的特制:strong, weak, copy
strong
//OC在定義對(duì)象類型屬性的時(shí)候默認(rèn)的特質(zhì)就是strong
//當(dāng)我們把一個(gè)對(duì)象B賦值給對(duì)象A的的屬性之后倾芝,對(duì)象A就持有B讨勤,
//B的引用計(jì)數(shù)就會(huì)加一,對(duì)象A還在晨另,對(duì)象B就不會(huì)被銷毀和釋放
//使用strong會(huì)出現(xiàn)一種叫循環(huán)引用的問題
@interface Person : NSObject
@end
@interface Car : NSObject
@property (nonatomic, strong) Person *driver;
@end
//只要Car對(duì)象沒被銷毀潭千, Person對(duì)象也不會(huì)被銷毀
//但如果司機(jī)也想知道當(dāng)前駕駛的車是哪一輛,
//這個(gè)時(shí)候給司機(jī)增加一個(gè)汽車屬性借尿,代碼如下:
@class Car;
@interface Person : NSObject
@property (nonatomic, strong) Car *car;
@end
@interface Car : NSObject
@property (nonatomic, strong) Person *driver;
@end
//這時(shí)司機(jī)和汽車相互引用刨晴,且他們的屬性都有strong特質(zhì),
//它們會(huì)使得對(duì)方引用計(jì)數(shù)都加一
//如果沒有任何變量指向這兩個(gè)對(duì)象時(shí)路翻,表示它們已經(jīng)沒用了狈癞,它們本應(yīng)該被銷毀,
//可是這倆對(duì)象卻不會(huì)被銷毀帚桩,因?yàn)樗麄兓ハ嘁弥诩荩糜?jì)數(shù)都還為1.
//它們永遠(yuǎn)不會(huì)被釋放,永遠(yuǎn)占著內(nèi)存
//這就是內(nèi)存泄露問題
//所以O(shè)C增加了一個(gè)屬性特質(zhì):weak
weak
//如果一個(gè)屬性被說明成weak账嚎,那當(dāng)它引用其他對(duì)象的時(shí)候莫瞬,它不會(huì)增加對(duì)方的引用計(jì)數(shù)
//如果這個(gè)對(duì)象被銷毀了,這個(gè)屬性的值就會(huì)自動(dòng)變成nil郭蕉,就避免了C語言里的懸掛指針問題
//因?yàn)槭褂脀eak沒有增加對(duì)方的引用計(jì)數(shù)疼邀,所以就不會(huì)造成循環(huán)引用問題
@class Car;//類的前置聲明,因?yàn)樵诙xPerson類的時(shí)候召锈,使用了Car類旁振,此時(shí)Car類未被聲明,所以需要這個(gè)前置聲明
@interface Person : NSObject
@property (nonatomic, weak) Car *car;
@end
@interface Car : NSObject
@property (nonatomic, strong) Person *driver;
@end
copy
//對(duì)于一個(gè)對(duì)象類型的屬性來說,當(dāng)我們給這個(gè)屬性賦值的時(shí)候拐袜,實(shí)際存儲(chǔ)的是這個(gè)對(duì)象的引用
//也就會(huì)存在一種可能吉嚣,當(dāng)我們給屬性賦值之后,我們還可以在外部去修改這個(gè)對(duì)象的值蹬铺,
//從而影響到屬性的值
@interface People : NSObject
@property (nonatomic, strong) NSString *name;//People類有一個(gè)NSString類型的屬性name
@end
People *p = [[People alloc] init];
NSMutableString *name = [NSMutableString stringWithString:@"Hello"];
p.name = name;//在對(duì)象p完全不知情的情況下尝哆,name屬性被改了,之前name屬性是被賦值為Hello甜攀。
NSLog(@"name: %@", p.name);
[name appendString:@"World!"];
NSLog(@"name: %@", p.name);
//把name屬性的strong特質(zhì)改為copy特質(zhì)秋泄,再操作 p.name = name 這句的時(shí)候,實(shí)際上是給一個(gè)復(fù)制出來的新對(duì)象進(jìn)行賦值规阀,并不會(huì)影響之前的屬性賦值
屬性的實(shí)現(xiàn)部分
如果我們聲明了一條屬性恒序,OC會(huì)幫我們自動(dòng)定義對(duì)應(yīng)的變量。默認(rèn)情況下:
//@property NSString *firstName;的實(shí)現(xiàn)
NSString *_firstName;
- (void)setFirstName:(NSString *)firstName;
- (NSString *)firstName;
- (void)setFirstName:(NSString *)firstName {
…
}
- (NSString *)firstName {
…
}
//_firstName是OC自動(dòng)幫我們生成的谁撼,如果我想用自己定義的變量名歧胁,
//則可以在類的實(shí)現(xiàn)部分使用@synthesize關(guān)鍵字
@interface People : NSObject
@property (nonatomic, strong) NSString *firstName;
@end
@implementation People
@synthesize firstName = _fname;
@end
//這樣屬性為firstName生成的變量名就變成了_fname
小結(jié)
屬性聲明的語法
屬性的特質(zhì)
小結(jié)