“屬性”(property)是Objective-C的一項特性,用于封裝對象中的數(shù)據(jù)。使用屬性之后,編譯器會自動寫出一套存取方法,用以訪問給定類型中具有給定名稱的變量。該過程由編譯器在編譯期執(zhí)行,編輯器看不到這些合成方法的源代碼,編譯器還要自動向類中添加適當(dāng)?shù)膶嵗兞浚⑶以趯傩悦疤砑酉聞澗€,作為實例變量的名字。
1.常用關(guān)鍵字
@synthesize : 用屬性property之后,會生成實例變量,默認(rèn)情況下是:_firstName,我們可以通過synthesize對實例變量名通過如下方式進(jìn)行修改:
@ synthesize firstName = _myfirstName;@dynamic : 它可以用于阻止編譯器自動合成存取方法和實例變量。
2.屬性特質(zhì)
- 原子性(atomic,nonatomic)
atomic:具備atomic特質(zhì)的獲取方法會通過鎖定機(jī)制來確保其操作的原子性。如果兩個線程讀寫同一屬性,無論何時總能看到有效的屬性值。
nonatomic:不加鎖,當(dāng)一個線程在改寫屬性值時另外一個線程闖入,可能會把尚未修改好的的屬性值讀取出來,讀取到錯誤的屬性值。
一般情況下我們都只是用nonatomic,原因如下:
(1). 在iOS中使用同步鎖開銷較大,會帶來性能問題。
(2). 即使屬性設(shè)置成原子性的也不能保證“線程安全”,要實現(xiàn)線程安全還需要更深層次的鎖定機(jī)制才行。 - 讀寫權(quán)限 (readwrite, readonly)
readwrite: 擁有g(shù)etter/setter方法,若由synthesize實現(xiàn),編譯器會自動生成這兩個方法。
readonly:僅擁有g(shù)etter方法,若由synthesize實現(xiàn),編譯器會自動生獲取方法。
3.內(nèi)存管理語義
- assign: "設(shè)置方法"之后執(zhí)行針對“純量類型”的簡單的賦值操作,如:NSIntager,CGFloat.
- strong:表明該屬性定義一種“擁有關(guān)系”,為這種屬性設(shè)置新值時,設(shè)置方法會先保留新值,并釋放舊值,再把新值設(shè)置上去。
- weak :該特質(zhì)表明屬性定義一種“非擁有關(guān)系”,為這種屬性設(shè)置新值時,設(shè)置方法既不保留新值,也不釋放舊值。
- copy:該設(shè)置方法并不保留新值,而是將其“拷貝”(copy),常用于NSString, NSDictionary, NSArray等數(shù)據(jù)類型來保護(hù)其封裝性。
原因:當(dāng)屬性類型為NSString* 時,傳遞給設(shè)置方法的新值有可能指向了個NSMutableString類的實例,這個類是NSString的子類,表示一種可以修改其值的字符串,若此時不拷貝字符串,那么設(shè)置完屬性之后,字符串的值就可能再對象不知情的情況下遭人更改。所以,這時就要拷貝一份“不可變”的字符串,以確保對象中的字符串值不會無疑將變動。只要實現(xiàn)屬性所用的對象是“可變的”,就應(yīng)該在設(shè)置屬性值時拷貝一份。
4.方法名
getter=<name> :指定“獲取方法”的方法名,如果某屬性是Boolean型時,想在獲取方法前加一個“is”前綴,就可以通過該方法來指定。如:
@property (nonatomic, getter = isOn) Bool on;
案例說明
-
weak與strong的區(qū)別
//copy,復(fù)制一份,相當(dāng)于retain,retainCount加1 @property (nonatomic, copy) NSString *string1; //weak,與assign類似,retainCount不加1 //指針指向的地址被釋放時,指針將被賦值為nil,有效的防止野指針。 @property (nonatomic, weak) NSString *string2; //string1指向值為“string 1”的對象,retainCount=1 self.string1 = [[NSString alloc] initWithUTF8String:"string 1"]; //string2也指向值為“string 1”的對象,但是是若引用,retainCount不變 self.string2 = self.string1; //將string1 指向nil, string1指向的地址被銷毀,值為“string 1”的對象的 retainCount=0, self.string1 = nil; //weak型的string2的指針也將被賦值為nil NSLog(@"String 2 = %@---%p", self.string2,self.string2); //打印結(jié)果:2016-07-05 13:55:27.400 Test[1328:34343] String 2 = (null)---0x0
如果將上面string2的特性weak更改成strong或者copy,string2將不會指向nil,打印的結(jié)果如下:
2016-07-05 14:13:57.352 Test[1391:43333] String 2 = string 1---0x79ff0d30
- copy與strong的區(qū)別
從上面看出copy和strong都能實現(xiàn)一種“擁有關(guān)系”,也就是使retainCount 加1,為什么一般情況下我們都是將NSString,NSArray,NSDictionary等屬性設(shè)置為copy,而不是strong呢?
那是因為,NSString,NSArray,NSDictionary等類,都有對應(yīng)的可變類型,如NSMutableString,NSMutableArray,NSMutableDictionary。NSMutableString這個類是NSString類的子類,表示一種可以修改其值的字符串,若此時不拷貝字符串,那么設(shè)置完屬性之后,字符串的值就可能再對象不知情的情況下遭人更改。
案例如下:
@property (nonatomic, copy) NSString *string1;
@property (nonatomic, strong) NSString *string3;
@property (nonatomic, weak) NSString *string2;
NSMutableString *mStr = [NSMutableString stringWithFormat:@"abc"];
self.string1 = mStr;
self.string2 = mStr;
self.string3 = mStr;
[mStr appendString:@"de"];
NSLog(@"mStr:%@---%p---%p", mStr,mStr,&mStr);
NSLog(@"copyStr:%@---%p---%p", self.string1,self.string1, &_string1);
NSLog(@"strongStr:%@---%p---%p", self.string3,self.string3, &_string3);
NSLog(@"weakStr:%@---%p---%p", self.string2,self.string2, &_string2);
打印的結(jié)果如下:
2016-07-05 14:23:32.886 Test[1458:51397] mStr:abcde---0x7a67eaf0---0xbff2201c
2016-07-05 14:23:32.886 Test[1458:51397] copyStr:abc---0x7a67e410---0x7b06587c
2016-07-05 14:23:32.886 Test[1458:51397] weakStr:abcde---0x7a67eaf0---0x7b065880
2016-07-05 14:23:32.886 Test[1458:51397] strongStr:abcde---0x7a67eaf0---0x7b065884
由上面的打印結(jié)果可以看出:
1、設(shè)置特性為copy的string1,在執(zhí)行[mStr appendString:@"de"];后沒有被修改,而設(shè)置為strong,weak的屬性都遭到修改。
2、strong對應(yīng)的*string3、weak對應(yīng)的*string2指向的指針和*mStr指向的地址相同,說明他們指向的是*mStr相同的地址,他們的區(qū)別只存在于計數(shù)器是否加1。而copy對應(yīng)的*string2卻是指向不同于*mStr指向的地址,說明它是復(fù)制了一份重新開辟的內(nèi)存,并且retainCount加1。