Effective Objective-C 2.0讀書筆記(二)

3.用枚舉表示狀態,選項,狀態碼

  1. 用枚舉來表示狀態機的狀態,傳遞給方法的選項以及狀態碼等值時,能使這些狀態更加通俗易懂

  2. 如果把傳遞給某個方法的選項表示為枚舉類型,而多個選項又可同時使用,那么就將各選項值定義為2的冪,以便通過按位操作將其組合起來

enum UIViewAutoresizing {
    UIViewAutoresizingNone = 0,
    UIViewAutoresizingFlexibleLeftMargin    = 1 << 0,
    UIViewAutoresizingFlexibleWidth         = 1 << 1,
    UIViewAutoresizingFlexibleRightMargin   = 1 << 2,
    UIViewAutoresizingFlexibleTopMargin     = 1 << 3,
    UIViewAutoresizingFlexibleHeight        = 1 << 4,
    UIViewAutoresizingFlexibleBottomMargin  = 1 << 5
}
每個枚舉值的二進制表示,以及對其中兩個枚舉值執行按位或操作之后的二進制值
  1. 用NS_ENUM與NS_OPTIONS宏來定義枚舉類型,并指明其底層數據類型.這樣做可以確保枚舉是用開發者所選的底層數據類型實現出來的,而不會采用編譯器所選的類型.

用按位或運算來操作兩個枚舉值時,C++編譯模式的處理辦法與非C++模式不一樣.作為選項的枚舉值經常需要用按位或運算來組合.在用或運算操作兩個枚舉值時,C++認為運算結果的數據類型應該是枚舉的底層數據類型,也就是NSUInteger.而且C++不允許將這個底層類型"隱式轉換"為枚舉類本身.這時使用NS_ENUM定義枚舉,而且編譯器按照C++模式(也可能是Objective-C模式)編譯時,則會給出以下報錯:
error: cannot initialize a variable of type '枚舉類型' with an rvalue of type 'int'
如果想編譯這行代碼,就要將按位或操作的結果顯示轉換.所以在C++模式下應該用另一種方式定義NS_OPTIONS宏,以便省去類型轉換操作.
鑒于此,凡是需要按位或操作來組合的枚舉都應使用NS_OPTIONS定義.若是枚舉不需要互相組合,則應使用NS_ENUM來定義.

  1. 在處理枚舉類型的switch語句中不要實現default分支.這樣的話,加入新枚舉之后,編譯器就會提示開發者:switch語句并未處理所有枚舉.


    switch語句中處理枚舉類型

4.屬性

關鍵字

1.@property
它可以自動寫出一套存取方法

@interface EOCPerson : NSObject
@property NSString *firstName;
@property NSString *lastName;
@end
@interface EOCPerson : NSObject
- (NSString *)firstName;
- (void)setFirstName:(NSString *)firstName;
- (NSString *)lastName;
- (void)setLastName:(NSString *)lastName;
@end

上面兩種寫法對使用者來說是等效的

2.點語法
在使用了點語法之后,編譯器會把點語法轉換為對存取方法的調用

EOCPerson *aPerson = [EOCPerson new];
    
aPerson.firstName = @"Bob";//等同于
[aPerson setFirstName:@"Bob"];
    
NSString *lastName = aPerson.lastName;//等同于
NSString *lastName = [aPerson lastName];

3.自動合成
使用屬性之后,編譯器會自動編寫訪問這些屬性所需的方法.這個過程由編譯器在編譯期執行,所以在編輯器里是看不到這些"合成方法"的源代碼的.除了生成方法代碼之外,編譯器還會自動向類中添加適當類型的實例變量,并且在屬性名前面加下劃線,以此作為實例變量的名字.

@interface EOCPerson : NSObject
@property NSString *firstName;
@property NSString *lastName;
@end
//生成的實例變量為_firstName和_lastName

4.@synthesize
它用來指定實例變量名字

@implementation EOCPerson
@synthesize firstName = _myFirstName;
@synthesize lastName = _myLastName;
@end
//此時的實例變量名變為了_myFirstName和_myLastName,而不是之前的_firstName和_lastName

5.@dynamic(協議的繼承會用到此語法)
它會告訴編譯器,不要自動創建實現屬性所用的實例變量,也不要為其創建存取方法.而且,在編譯訪問屬性的代碼時,即使編譯器發現沒有定義存取方法,也不會報錯.

更多關于dynamic關鍵字的知識請看:Objective-C中的@dynamic

屬性特質

@property (nonatomic, readwrite, copy) NSString *firstName;

1.原子性
在默認情況下,由編譯器所合成的方法會通過鎖定機制確保其原子性(atomicity).如果屬性具備nonatomic特質,則不使用同步鎖.注意,盡管沒有名為"atomic"的特質,但是仍然可以在屬性特質中寫明這一點,編譯器不會報錯(如果某屬性不具備nonatomic特質,那它就是"原子的"(atomic)).

在并發操作中,如果某操作具備整體性,也就是說,系統其他部分無法觀察到其中間步驟所生成的臨時結果,而只能看到操作前與操作后的結果,那么該操作就是"原子的"(atomic).原子性

在開發iOS程序時應該使用nonatomic屬性,因為atomic屬性會嚴重影響性能.

2.讀/寫權限

  • 具備readwrite(讀寫)特質的屬性擁有"獲取方法"(getter)與"設置方法"(setter).若該屬性由@synthesize實現,則編譯器會自動生成這兩個方法.
  • 具備readonly(只讀)特質的屬性僅擁有獲取方法,只有當屬性由@synthesize實現時,編譯器才會為其合成獲取方法.你可以用此特質把某個屬性對外公開為只讀屬性,然后再"class-continuation分類"中將其重新定義為讀寫屬性.

3.內存管理語義
屬性用于封裝數據,而數據則要有"具體所有權語義"(concrete ownership semantic).下面的這些特質只會影響"設置方法"

  • assign "設置方法"只會執行針對"純量類型"(例如CGFloat或NSInteger等)的簡單賦值操作
  • strong 此特質表明該屬性定義了一種"擁有關系".為這種屬性設置新值時,設置方法會先保留新值,并釋放舊值,然后再將新值設置上去.
  • weak 此特質表明該屬性定義了一種"非擁有關系".為這種屬性設置新值時,設置方法既不保留新值,也不釋放舊值.此特質同assign類似,然而在屬性所指的對象遭到摧毀時,屬性也會清空.
  • unsafe_unretained 此特質的寓意和assign相同,但是它適用于"對象類型",該特質表達一種"非擁有關系",當目標對象遭到摧毀時,屬性值不會自動清空,這一點與weak有區別.
  • copy 此特質所表達的所屬關系與strong類似.然而設置方法并不保留新值,而是將其"拷貝".當屬性類型為NSString *時,經常用此特質來保護其封裝性,因為傳遞給設置方法的新值有可能指向一個NSMutableNSString類的實例.這個類似NSString的子類,表示一種可以修改其值的字符串,此時若是不拷貝字符串,那么設置完屬性之后,字符串的值就可能會在對象不知情的情況下遭人更改.所以,這是就要拷貝一份"不可變"的字符串,確保對象中的字符串值不會無意間變動.只要實現屬性所用的對象是"可變的",就應該在設置新屬性值時拷貝一份.

4.方法名

  • getter=<name> 指定"獲取方法"的方法名.
@property (nonatomic, getter=isOn) BOOL on;
  • setter=<name> 指定"設置方法"的方法名.這種用法不太常見

在設置屬性鎖對應的實例變量時,一定要遵從該屬性所聲明的語義.

@interface EOCPerson : NSObject

@property (nonatomic,copy) NSString *firstName;
@property (nonatomic,copy) NSString *lastName;

- (id)initWithFirstName:(NSString *)firstName
               lastName:(NSString *)lastName;

@end

在實現上述初始化方法時,一定要遵循屬性定義中宣稱的"copy"語義

- (id)initWithFirstName:(NSString *)firstName lastName:(NSString *)lastName {
    if (self = [super init]) {
        _firstName = [firstName copy];
        _lastName = [lastName copy];
    }
    return self;
}
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,825評論 6 546
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,814評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,980評論 0 384
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 64,064評論 1 319
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,779評論 6 414
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 56,109評論 1 330
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 44,099評論 3 450
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 43,287評論 0 291
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,799評論 1 338
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,515評論 3 361
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,750評論 1 375
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,221評論 5 365
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,933評論 3 351
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,327評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,667評論 1 296
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,492評論 3 400
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,703評論 2 380

推薦閱讀更多精彩內容