屬性
“屬性”(property)是OC的一項特性,用于封裝物件中的資料,
@property
-
@Property是宣告屬性的語法(
@property = ivar + getter + setter),OC物件通常會把其所需的資料保存為各種實體變數(
ivar),實體變數一般通過“存取方法”(accessmethod)來訪問,什么是存取方法:
getter和setter方法(access method = getter + setter),其中getter用于獲取變數value, 而setter用于寫入value, -
@Property可以快速方便的為實體變數創建存取器,
// Man.h
#import <Foundation/Foundation.h>
@interface Man : NSObject
@property (nonatomic,strong)NSString *name;
@property (nonatomic,strong)NSString *sex;
@end
與下面的寫法等效
// Man.h
#import <Foundation/Foundation.h>
@interface Man : NSObject
{
// 實體變數
NSString *name;
NSString *sex;
}
// setter
- (void)setName:(NSString *)newName;
// getter
- (NSString *)name;
// setter
- (void)setSex:(NSString *)newSex;
// getter
- (NSString *)sex;
@end
- 通常使用“點語法” 來讓編譯器自動呼叫相關的存取方法(
access method = getter + setter),self. name = @"sky"; NSString *name = self. name;點語法有什么優勢呢?
省時,省力 :如果使用了屬性,編譯器會自動撰寫訪問屬性所需的方法,這個程序由編譯器在編譯期執行,看不到這些
get set源代碼,編譯器會自動向類中添加適當型別的實體變數,并且在屬性名前添加下劃線,
-
如果你不想讓編譯器自動合成存取方法,則可以自己實作,如果你只實作了其中一個存取方法,那么另一個還是會由編譯器來合成,
-
當我們同時重寫了
setter and getter方式時,系統會報錯,原因是找不到實體變數,其解決方法: 在.m的檔案中使用@synthesize,
@synthesize
-
@synthesize是為屬性添加一個實體變數名,或者說別名,同時會為該屬性生成setter/getter方法, -
在
protocol中使用property只會生成setter和getter方法宣告,我們使用屬性的目的,是希望遵守我協議的物件能實作該屬性,需要使用@synthesize生成setter和getter, -
當你在子類中多載了父類中的屬性,你必須 使用
@synthesize來手動合成ivar, -
當我們同時重寫了
setter and getter方式時,需要在.m的檔案中使用@synthesize,// Man.m #import "Man.h" @implementation Man @synthesize name = _name; // setter - (void)setName:(NSString *)name { _name = name; } // getter - (NSString *)name { return _name; } @end-
@synthesize name = _name
-
_name是成員變數 -
name是屬性 -
作用是告訴編譯器
name屬性為_name實體變數生成setter and getter方法的實作 -
name屬性的setter方法是setName,它操作的是_name這個變數 -
在
@synthesize中定義與變數名不同的setter和getter的命名,以此來保護變數不會被不恰當的訪問(setter=<name>這種不常用,也不推薦使用)//setter=<name>這種不常用,也不推薦使用 @property (nonatomic, setter = mySetter,getter = myGetter ) NSString *name; @property (nonatomic,getter = isHidden ) BOOL hidden;
-
-
-
@property有兩個對應的詞,一個是@synthesize,一個是@dynamic,如果@synthesize和@dynamic都沒寫,那么默認的就是@syntheszie var = _var, -
如果某屬性已經在某處實作了自己的
setter/getter,可以使用@dynamic來阻止@synthesize自動生成新的setter/getter覆寫,
@dynamic
-
@dynamic告訴編譯器:屬性的setter與getter方法由用戶自己實作,不自動生成,(當然對于readonly的屬性只需提供getter即可), -
假如一個屬性被宣告為
@dynamic var,然后你沒有提供@setter方法和@getter方法,編譯的時候沒問題,但是當程式運行到instance.var = someVar,由于缺setter方法會導致程式崩潰,或者當運行到someVar = var時,由于缺getter方法同樣會導致崩潰, -
編譯時沒問題,運行時才執行相應的方法,這就是所謂的動態系結,
// Man.h
#import <Foundation/Foundation.h>
@interface Man : NSObject
@property (nonatomic,strong)NSString *name;
@end
// Man.m
#import "Man.h"
@implementation Man
@dynamic name;
// setter
// - (void)setName:(NSString *)name
// {
// _name = name;
// }
// getter
- (NSString *)name
{
return _name;
}
@end
呼叫時會出現崩潰
Man *man = [[Man alloc] init];
man.name = @"sky";//缺 setter 方法會導致程式崩潰
NSString *name = man.name;//缺 getter 方法同樣會導致崩潰
屬性特質
原子性
-
atomic(默認):atomic意為操作是原子的,意味著只有一個執行緒訪問實體變數(生成的setter和getter方法是一個原子操作),atomic是執行緒安全的,至少在當前的存取器上是安全的,它是一個默認的特性,但是很少使用,因為比較影響效率, -
nonatomic:nonatomic意為操作是非原子的,可以被多個執行緒訪問,它的效率比atomic快,但不能保證在多執行緒環境下的安全性,開發中常用, -
開發iOS程式時應該使用
nonatomic屬性,因為atomic(同步鎖)屬性嚴重影響性能,該屬性使用了同步鎖,會在創建時生成一些額外的代碼用于幫助撰寫多執行緒程式,這會帶來性能問題,通過宣告nonatomic可以節省這些雖然很小但是不必要額外開銷,
存取器控制
-
readwrite(默認):readwrite是默認值,表示該屬性同時擁有setter和getter, -
readonly:readonly表示只有getter沒有setter, -
有時候為了語意更明確可能需要自定義訪問器的名字,
//setter=<name>這種不常用,也不推薦使用
@property (nonatomic, setter = mySetter,getter = myGetter ) NSString *name;
@property (nonatomic,getter = isHidden ) BOOL hidden;
記憶體管理
-
assign(默認):assign用于非指標變數(值)型別,統一由系統堆疊進行記憶體管理,一般用于基礎型別和C資料型別,如int、float、double和NSInteger,CGFloat等表示單純的復制,還包括不存在所有權關系的物件,比如常見的delegate, -
retain:在setter方法中,需要對傳入的物件進行參考計數加1的操作, -
strong:strong是在IOS引入ARC的時候引入的關鍵字,是retain的一個可選的替代,對傳入的物件的強參考,會增加物件的參考計數,strong跟retain的意思相同并產生相同的代碼,但是語意上更好更能體現物件的關系, -
weak:對傳入的物件的弱參考,不增加物件的參考計數,也不持有物件,當物件消失后指標自動指向nil, -
copy:與strong類似,但區別在于copy是創建一個新物件,strong是創建一個指標,參考物件計數加1,
舉例說明weak與strong與copy屬性特質的差異
- 首先創建兩個自定義的
Person類的實體變數,并分別用weak與strong修飾,
@property (nonatomic,strong) Person *strongPerson;
@property (nonatomic,weak) Person *weakPerson;
- 將
strongPerson屬性置nil,
self.strongPerson = [[Person alloc] init];
self.weakPerson = self.strongPerson;
self.strongPerson = nil;
NSLog(@"strongStr=%@,weakStr=%@",self.strongPerson,self.weakPerson);
輸出結果為:strongStr=(null),weakStr=(null) ,說明weak修飾的屬性并不會使參考計數增加,
- 如果使用NSString類進行上述類似操作,得到的結果是不同的,
@property (nonatomic,strong) NSString *strongStr;
@property (nonatomic,weak) NSString *weakStr;
···
self.strongStr = @"string";
self.weakStr = self.strongStr;
self.strongStr = nil;
NSLog(@"strongStr=%@,weakStr=%@",self.strongStr,self.weakStr);
輸出結果為:strongStr=(null),weakStr=string ,這里主要是因為NSString型別的賦值默認會加上copy,而copy會創建一個新的物件,這里的賦值陳述句其實是
self.strongStr = [@"string" copy];
self.weakStr = [self.strongStr copy];
- 將
weakPerson屬性置nil,
self.strongPerson = [[Person alloc] init];
self.weakPerson = self.strongPerson;
self.weakPerson = nil;
NSLog(@"strongStr=%@,weakStr=%@",self.strongPerson,self.weakPerson);
輸出結果如下:strongStr=<Person: 0x600000007d50>,weakStr=(null) ,說明weak修飾的屬性只是對物件的弱參考,并不會真正的持有該物件,
- 新建一個
Person類實體變數p,賦值strongPerson后將p置nil,
Person *p = [[Person alloc] init];
self.strongPerson = p;
self.weakPerson = self.strongPerson;
p = nil;
NSLog(@"strongStr=%@,weakStr=%@",self.strongPerson,self.weakPerson);
輸出結果為:strongStr=<Person: 0x600000200b50>,weakStr=<Person: 0x600000200b50> ,因為strong屬性會強參考該物件并使該物件的參考計數+1,所以即使把p設定為nil,該物件也并沒有釋放,要想釋放該物件,還得把strongStr設定為nil:self.strongPerson = nil; ,這樣輸出結果才為 strongStr=(null),weakStr=(null),
- 在給
Person類加了一個name屬性,并用copy修飾 :(@property (nonatomic,copy) NSString *name),
NSString *a = @"xiaoming";
Person *p = [[Person alloc] init];
p.name = a;
NSLog(@"before p.name=%@",p.name);
a = @"xiaohua";
NSLog(@"after p.name=%@",p.name);
輸出結果:before p.name=xiaoming 與 after p.name=xiaoming,因為copy關鍵字修飾的屬性是將物件拷貝一份賦值,所以你改變原物件并不會對拷貝后的物件有任何改變,
注:用@property宣告 NSString、NSArray、NSDictionary 經常使用copy關鍵字,是因為他們有對應的可變型別:NSMutableString、NSMutableArray、NSMutableDictionary,他們之間可能進行賦值操作,為確保物件中的字串值不會無意間變動,應該在設定新屬性值時拷貝一份.
要點
-
可以用
@property語法來定義物件中所封裝的資料, -
通過“修飾詞”來指定存盤資料所需的正確語意,
-
在設定屬性所對應的實體變數時,一定要遵從該屬性所宣告的語意,
-
開發iOS程式時應該使用
nonatomic屬性,因為atomic(同步鎖)屬性嚴重影響性能,
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/11423.html
標籤:iOS
