Objective-C中的@property

1.@property是什么

@Property是聲明屬性的語法,它可以快速方便的為實(shí)例變量創(chuàng)建存取器,并允許我們通過點(diǎn)語法使用存取器始衅。

存取器(accessor):指用于獲取和設(shè)置實(shí)例變量的方法肿男。用于獲取實(shí)例變量值的存取器是getter赊舶,用于設(shè)置實(shí)例變量值的存取器是setter草姻。

2.創(chuàng)建存取器

2.1 手工創(chuàng)建存取器

我們先看兩段代碼:

// Car.h

#import <Foundation/Foundation.h>

@interface Car : NSObject
{
    // 實(shí)例變量
    NSString *carName;
    NSString *carType;
}

// setter                                   
- (void)setCarName:(NSString *)newCarName; 
                                            
// getter
- (NSString *)carName;

// setter
- (void)setCarType:(NSString *)newCarType;

// getter
- (NSString *)carType;

@end  

上面的代碼中carNamecarType就是Car的實(shí)例變量瀑构,并且可以看到分別對這兩個實(shí)例變量聲明了get/set方法笨腥,即存取器目尖。

#import "Car.h"

@implementation Car

// setter
- (void)setCarName:(NSString *)newCarName
{
    carName = newCarName;
}

// getter
- (NSString *)carName
{
    return carName;
}

// setter
- (void)setCarType:(NSString *)newCarType
{
    carType = newCarType;
}

// getter
- (NSString *)carType
{
    return carType;
}

@end

上面代碼是對實(shí)例變量存取器的實(shí)現(xiàn)馒吴。我們可以看到,存取器就是對實(shí)例變量進(jìn)行賦值和取值瑟曲。按照約定賦值方法以set開頭饮戳,取值方法以實(shí)例變量名命名。
我們看看如何使用:

// main.m

#import "Car.h"

int main(int argc, char * argv[])
{
    @autoreleasepool {
        Car *car = [[Car alloc] init];
        [car setCarName:@"Jeep Cherokee"];
        [car setCarType:@"SUV"];
        NSLog(@"The car name is %@ and the type is %@",[car carName],[car carType]);      
    }
    return 0;
}

上面的代碼中我們注意到洞拨,對象Car使用了消息語法扯罐,也就是使用方括號的語法給存取器發(fā)送消息。
返回結(jié)果為:

The car name is Jeep Cherokee and the type is SUV

2.2 使用@Property創(chuàng)建存取器

// Car.h

#import <Foundation/Foundation.h>

@interface Car : NSObject
{
    // 實(shí)例變量
    NSString *carName;
    NSString *carType;
}

@property(nonatomic,strong) NSString *carName;
@property(nonatomic,strong) NSString *carType;

@end

上面代碼中烦衣,我們使用@property聲明兩個屬性歹河,名稱與實(shí)例變量名稱相同(讓我們先忽略nonatomicstrong)。

// Car.m

#import "Car.h"

@implementation Car

@synthesize carName;
@synthesize carType;

@end

在.m文件中我們使用@synthesize自動生成這兩個實(shí)例變量的存取器花吟,并且隱藏了存取器秸歧,雖然我們看不到存取器,但它們確實(shí)是存在的衅澈。

// main.m

int main(int argc, char * argv[])
{
    @autoreleasepool {
        Car *car = [[Car alloc] init];
        car.carName = @"Jeep Compass";
        car.carType = @"SUV";
        NSLog(@"The car name is %@ and the type is %@",car.carName,car.carType); 
    }
    return 0;
}

在上面的代碼中我們可以注意到寥茫,Car對象使用點(diǎn)語法給存取器發(fā)送消息,并且get與set的語法是相同的矾麻,所以這里的點(diǎn)語法可以根據(jù)語境判斷我們是要賦值還是取值纱耻。

當(dāng)然我們也依然可以使用消息語法來使用:

// main.m

int main(int argc, char * argv[])
{
    @autoreleasepool {
        Car *car = [[Car alloc] init];
        
        // 點(diǎn)語法
//        car.carName = @"Jeep Compass";
//        car.carType = @"SUV";
//        NSLog(@"The car name is %@ and the type is %@",car.carName,car.carType);
    
        // 消息語法
        [car setCarName:@"Jeep Compass"];
        [car setCarType:@"SUV"];
        NSLog(@"The car name is %@ and the type is %@",[car carName],[car carType]);       
    }
    return 0;
}

上面兩段代碼的執(zhí)行結(jié)果都是:

The car name is Jeep Compass and the type is SUV

總結(jié):@property等同于在.h文件中聲明實(shí)例變量的get/set方法,@synthesize等同于在.m文件中實(shí)現(xiàn)實(shí)例變量的get/set方法险耀。使用@propertysynthesize創(chuàng)建存取器要比手動聲明兩個存取方法(gettersetter)更簡單弄喘。而且我們在使用屬性時可以使用點(diǎn)語法賦值或取值,語法更簡單甩牺,更符合面向?qū)ο缶幊獭?/p>

3.不必單獨(dú)聲明示例變量

如果使用@Property蘑志,就不必單獨(dú)聲明實(shí)例變量了。因?yàn)樵跊]有顯示提供示例變量聲明的前提下贬派,系統(tǒng)會自動幫你生成實(shí)例變量急但。我們通過以下代碼來說明:

// Car.h

#import <Foundation/Foundation.h>

@interface Car : NSObject

@property(nonatomic,strong) NSString *carName;
@property(nonatomic,strong) NSString *carType;

- (NSString *)carInfo;

@end

在.h文件中我們并沒有聲明實(shí)例變量,只是聲明了carNamecarType兩個屬性搞乏,以及一個carInfo方法波桩,返回值為NSString *

// Car.m

#import "Car.h"

@implementation Car

- (NSString *)carInfo
{
    return [NSString stringWithFormat:@"The car name is %@ and the type is %@",_carName,_carType];
}

@end

在.m文件中我們可以注意到请敦,在carInfo方法中我們使用了_carName_carType實(shí)例變量镐躲,這就是當(dāng)我們沒有顯示聲明實(shí)例變量時储玫,系統(tǒng)為我們自動生成的。命名規(guī)則是以_為前綴萤皂,加上屬性名撒穷,即_propertyName

其實(shí)在.m文件中實(shí)際是存在@synthesize聲明語句的裆熙,只是系統(tǒng)將其隱藏了:

@synthesize carName = _carName;
@synthesize carType = _carType;

那么如果我們不喜歡默認(rèn)的實(shí)例變量命名方法端礼,或者我們希望使用更有語義的名稱,應(yīng)該怎么做呢入录。其實(shí)很簡單:

// Car.m

#import "Car.h"

@implementation Car

@synthesize carName = i_am_car_name;
@synthesize carType = i_am_car_type;

- (NSString *)carInfo
{
    return [NSString stringWithFormat:@"The car name is %@ and the type is %@",i_am_car_name,i_am_car_type];
}

@end

通過上述代碼可以看到蛤奥,我們只需要通過@synthesize來聲明我們希望的實(shí)例變量名。

總結(jié):如果我們希望使用默認(rèn)的實(shí)例變量命名方式纷跛,那么我們在.m文件中就不需要使用@synthesize聲明,系統(tǒng)會幫我們自動完成邀杏。如果我們希望自己命名實(shí)例變量命贫奠,那么我們就使用@synthesize顯示聲明我們希望的實(shí)例變量名。

4.@property的特性

@property還有一些關(guān)鍵字望蜡,它們都是有特殊作用的唤崭,比如上述代碼中的nonatomicstrong

@property(nonatomic,strong) NSString *carName;
@property(nonatomic,strong) NSString *carType;

我把它們分為三類脖律,分別是:原子性谢肾,存取器控制,內(nèi)存管理小泉。

4.1 原子性

  • atomic(默認(rèn)):atomic意為操作是原子的芦疏,意味著只有一個線程訪問實(shí)例變量。atomic是線程安全的微姊,至少在當(dāng)前的存取器上是安全的酸茴。它是一個默認(rèn)的特性,但是很少使用兢交,因?yàn)楸容^影響效率薪捍,這跟ARM平臺和內(nèi)部鎖機(jī)制有關(guān)。
  • nonatomicnonatomicatomic剛好相反配喳。表示非原子的酪穿,可以被多個線程訪問。它的效率比atomic快晴裹。但不能保證在多線程環(huán)境下的安全性被济,在單線程和明確只有一個線程訪問的情況下廣泛使用。

4.2 存取器控制

  • readwrite(默認(rèn)):readwrite是默認(rèn)值涧团,表示該屬性同時擁有settergetter溉潭。
  • readonlyreadonly表示只有getter沒有setter净响。

有時候?yàn)榱苏Z意更明確可能需要自定義訪問器的名字:

@property (nonatomic, setter = mySetter:,getter = myGetter ) NSString *name;

最常見的是BOOL類型,比如標(biāo)識View是否隱藏的屬性hidden喳瓣〔鱿停可以這樣聲明:

@property (nonatomic,getter = isHidden ) BOOL hidden;

4.3 內(nèi)存管理

@property有顯示的內(nèi)存管理策略。這使得我們只需要看一眼@property聲明就明白它會怎樣對待傳入的值畏陕。

  • assign(默認(rèn)):assign用于值類型配乓,如intfloat惠毁、doubleNSInteger犹芹,CGFloat等表示單純的復(fù)制。還包括不存在所有權(quán)關(guān)系的對象鞠绰,比如常見的delegate腰埂。
@property(nonatomic) int running;  
@property(nonatomic,assign) int running;

以上兩段代碼是相同的。

setter方法中蜈膨,采用直接賦值來實(shí)現(xiàn)設(shè)值操作:

-(void)setRunning:(int)newRunning{  
    _running = newRunning;  
} 
  • retian:在setter方法中屿笼,需要對傳入的對象進(jìn)行引用計(jì)數(shù)加1的操作。
    簡單來說翁巍,就是對傳入的對象擁有所有權(quán)驴一,只要對該對象擁有所有權(quán),該對象就不會被釋放灶壶。如下代碼所示:
-(void)setName:(NSString*)_name{  
     //首先判斷是否與舊對象一致肝断,如果不一致進(jìn)行賦值。  
     //因?yàn)槿绻且粋€對象的話驰凛,進(jìn)行if內(nèi)的代碼會造成一個極端的情況:當(dāng)此name的retain為1時胸懈,使此次的set操作讓實(shí)例name提前釋放,而達(dá)不到賦值目的恰响。  
     if ( name != _name){  
          [name release];  
          name = [_name retain];  
     }  
} 
  • strongstrong是在IOS引入ARC的時候引入的關(guān)鍵字箫荡,是retain的一個可選的替代。表示實(shí)例變量對傳入的對象要有所有權(quán)關(guān)系渔隶,即強(qiáng)引用羔挡。strong跟retain的意思相同并產(chǎn)生相同的代碼,但是語意上更好更能體現(xiàn)對象的關(guān)系间唉。
  • weak:在setter方法中绞灼,需要對傳入的對象不進(jìn)行引用計(jì)數(shù)加1的操作。
    簡單來說呈野,就是對傳入的對象沒有所有權(quán)低矮,當(dāng)該對象引用計(jì)數(shù)為0時,即該對象被釋放后被冒,用weak聲明的實(shí)例變量指向nil军掂,即實(shí)例變量的值為0轮蜕。

注:weak關(guān)鍵字是IOS5引入的,IOS5之前是不能使用該關(guān)鍵字的蝗锥。delegate 和 Outlet 一般用weak來聲明跃洛。

  • copy:與strong類似,但區(qū)別在于實(shí)例變量是對傳入對象的副本擁有所有權(quán)终议,而非對象本身汇竭。

本文首發(fā)地址:Objective-C中的@property

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市穴张,隨后出現(xiàn)的幾起案子细燎,更是在濱河造成了極大的恐慌,老刑警劉巖皂甘,帶你破解...
    沈念sama閱讀 211,290評論 6 491
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件玻驻,死亡現(xiàn)場離奇詭異,居然都是意外死亡偿枕,警方通過查閱死者的電腦和手機(jī)璧瞬,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,107評論 2 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來益老,“玉大人彪蓬,你說我怎么就攤上這事寸莫∞嗝龋” “怎么了?”我有些...
    開封第一講書人閱讀 156,872評論 0 347
  • 文/不壞的土叔 我叫張陵膘茎,是天一觀的道長桃纯。 經(jīng)常有香客問我,道長披坏,這世上最難降的妖魔是什么态坦? 我笑而不...
    開封第一講書人閱讀 56,415評論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮棒拂,結(jié)果婚禮上伞梯,老公的妹妹穿的比我還像新娘。我一直安慰自己帚屉,他們只是感情好谜诫,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,453評論 6 385
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著攻旦,像睡著了一般喻旷。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上牢屋,一...
    開封第一講書人閱讀 49,784評論 1 290
  • 那天且预,我揣著相機(jī)與錄音槽袄,去河邊找鬼。 笑死锋谐,一個胖子當(dāng)著我的面吹牛遍尺,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播怀估,決...
    沈念sama閱讀 38,927評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼狮鸭,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了多搀?” 一聲冷哼從身側(cè)響起歧蕉,我...
    開封第一講書人閱讀 37,691評論 0 266
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎康铭,沒想到半個月后惯退,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,137評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡从藤,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,472評論 2 326
  • 正文 我和宋清朗相戀三年催跪,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片夷野。...
    茶點(diǎn)故事閱讀 38,622評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡懊蒸,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出悯搔,到底是詐尸還是另有隱情骑丸,我是刑警寧澤,帶...
    沈念sama閱讀 34,289評論 4 329
  • 正文 年R本政府宣布妒貌,位于F島的核電站通危,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏灌曙。R本人自食惡果不足惜菊碟,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,887評論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望在刺。 院中可真熱鬧逆害,春花似錦、人聲如沸蚣驼。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,741評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽隙姿。三九已至梅垄,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背队丝。 一陣腳步聲響...
    開封第一講書人閱讀 31,977評論 1 265
  • 我被黑心中介騙來泰國打工靡馁, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人机久。 一個月前我還...
    沈念sama閱讀 46,316評論 2 360
  • 正文 我出身青樓臭墨,卻偏偏與公主長得像,于是被迫代替她去往敵國和親膘盖。 傳聞我的和親對象是個殘疾皇子胧弛,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,490評論 2 348

推薦閱讀更多精彩內(nèi)容