第一條:了解Objective-C語言的起源
1.Objective-C語言的對象所占內(nèi)存總是分配在“堆空間”中列荔。
2.分配在堆中的內(nèi)存必須直接管理主经,而分配在棧上用于保存變量的內(nèi)存則會在其棧幀彈出時自動清理。
3.基本類型也被存放在棽沧Γ空間征堪。
第2條:在類的頭文件中盡量少引用其他頭文件
1.當一個類作為另一個類的屬性的類型時,只需聲明
@class className
有兩個好處:
(1) 減少編譯時間
(2)解決了兩個雷相互引用的問題背桐。
如果在各自頭文件中引入對方的頭文件优烧,則會導致“循環(huán)引用”。當解析其中一個頭文件時链峭,編譯器會發(fā)現(xiàn)它引入了另一個頭文件畦娄,而那個頭文件回過頭來引用了第一個頭文件。使用#import而非#include指令雖然不會導致死循環(huán)熏版,但這意味著兩個類里有一個無法被正確編譯纷责。
2.最好把協(xié)議單獨放在一個頭文件中。
3.委托協(xié)議就不能單獨寫一個頭文件了撼短。此時最好能在實現(xiàn)文件中聲明此類實現(xiàn)了委托協(xié)議再膳,并把這段代碼放到“class-continuation”分類里。這樣的話曲横,只要在實現(xiàn)文件中引入包含委托協(xié)議的頭文件即可喂柒。
第3條:多用字面量語法不瓶,少用與之等價的方法
1.字面量字符串
NSString *someString = @"Effective Objective-C 2.0";
2.字面數(shù)值
NSNumber *intNumber = @1;
NSNumber *floatNumber = @2.5f;
NSNumber *doubleNumber = @3.14159
NSNumber *boolNumber = @YES;
NSNumber *charNmuber = @'a';
int x = 5;
float y = 6.32f;
NSNumber *expressionNumber = @(x * y);
3.字面量數(shù)組
NSArray *animals = @[@"cat",@"dog",@"mouse",@"badger"];
NSString *dog = animals[1];
4.字面量字典
NSDictionary *personData = @{@"firstName":@"Matt",@"lastName":@"Galloway",@"age":@28};
NSString *lastName = personData[@"lastName"];
與數(shù)組一樣灾杰,用字面量語法創(chuàng)建字典時也有個問題蚊丐,那就是一旦有值為nil,便會拋出異常
5.可變數(shù)組與字典
mutableArray[1] = @"dog";
mutableDictionary[@"lastName"] = @"Galloway";
使用字面量語法創(chuàng)建出來的字符串艳吠、數(shù)組麦备、字典對象都是不可變的。若想要可變版本的對象昭娩,則需復制一份
NSMutableArray *mutable = [@[@1,@2,@3,@4,@5] mutableCopy];
第4條:多用類型變量凛篙,少用#define預處理指令
1.用以下方式定義的變量包含類型信息,其好處是清楚地描述了常量的含義栏渺。
static const NSTimeInterval kAnimationDuration = 0.3;
如果試圖修改由const修飾符所聲明的變量呛梆,那么編譯器就會報錯。而static修飾符則意味著改變量僅在定義此變量的編譯單元中可見(.m文件中)磕诊。
2.如果需要對外公開某個變量填物,應該這樣定義:
// In the header file
extern NSString *const EOCStringConstant;
// In the implementation file
NSString *const EOCStringConstant = @"VALUE";
這樣定義常量優(yōu)于使用#define預處理指令,因為編譯器會確保常量值不變霎终。一旦在.m中定義好滞磺,即可隨處使用。而采用預處理指定所定義的常量可能會無意中遭人修改神僵,從而導致應用程序各個部分所使用的值互不相同雁刷。
第5條:用枚舉表示狀態(tài)、選項保礼、狀態(tài)碼
1.枚舉只是一種常量命名方式沛励,某個對象所經(jīng)歷的各種狀態(tài)就可以定義為一個簡單的枚舉集。
enum EOConnectionState {
EOConnectionStateDisconnected,
EOConnectionStateConnecting,
EOConnectionStateConnected,
};
// 定義變量的方式
enum EOConnectionState state = EOConnectionStateDisconnected,
若是每次不用敲入enum而只需寫EOConnectionState就好了炮障。要想這樣做目派,則需使用typedef關(guān)鍵字重新定義枚舉類型:
enum EOConnectionState {
EOConnectionStateDisconnected,
EOConnectionStateConnecting,
EOConnectionStateConnected,
};
typedef enum EOConnectionState EOConnectionState;
// 定義變量的方式
enum EOConnectionState state = EOConnectionStateDisconnected,
2.可以指明用何種“底層數(shù)據(jù)類型”來保存枚舉類型的變量。這樣做的好處是胁赢,可以向前生命枚舉變量了企蹭。若不指定底層數(shù)據(jù)類型,則無法向前聲明枚舉類型智末,因為編譯器不清楚底層數(shù)據(jù)類型的大小谅摄,所以在用到此類枚舉時,也就不知道究竟該給變量分配多少空間系馆。
指定底層數(shù)據(jù)類型所用的語法是:
enum EOCConectionStateConnectionState :NSInteger { /*...*/};
在向前聲明時指定底層數(shù)據(jù)類型:
enum EOCConectionStateConnectionState :NSInteger;
3.不使用編譯器所分配的序號送漠,而是手工指定某個枚舉成員所對應的值。
enum EOConnectionState {
EOConnectionStateDisconnected = 1,
EOConnectionStateConnecting, // 2
EOConnectionStateConnected, // 3
};
4.定義選項的時候由蘑,若這些選項可以彼此組合闽寡,各選項可通過“按位或操作符”來組合代兵。
enum UIViewAutoresizing {
UIViewAutoresizingNone = 0,
UIViewAutoresizingFlexibleLeftMargin = 1 << 0,
UIViewAutoresizingFlexibleWidth = 1 << 1,
UIViewAutoresizingFlexibleRightMargin = 1 << 2,
UIViewAutoresizingFlexibleTopMargin = 1 << 3,
UIViewAutoresizingFlexibleHeight = 1 << 4,
UIViewAutoresizingFlexibleBottomMargin = 1 << 5
};
因為每個枚舉值所對應的二進制表示中,只有一個二進制位的值是1爷狈。用“按位與操作符”即可判斷出是否已啟用某個選項:
enum UIViewAutoresizing resizing = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
if(resizing & UIViewAutoresizingFlexibleWidth){
// UIViewAutoresizingFlexibleWidth is set
}
5.凡是需要按位或操作來組合的枚舉都應使用NS_OPTIONS定義植影。若是枚舉不需要相互組合,則應使用NS_ENUM來定義涎永。
typedef NS_ENUM(NSInteger, UIViewAnimationTransition) {
UIViewAnimationTransitionNone,
UIViewAnimationTransitionFlipFromLeft,
UIViewAnimationTransitionFlipFromRight,
UIViewAnimationTransitionCurlUp,
UIViewAnimationTransitionCurlDown,
};
typedef NS_OPTIONS(NSUInteger, UIViewAutoresizing) {
UIViewAutoresizingNone = 0,
UIViewAutoresizingFlexibleLeftMargin = 1 << 0,
UIViewAutoresizingFlexibleWidth = 1 << 1,
UIViewAutoresizingFlexibleRightMargin = 1 << 2,
UIViewAutoresizingFlexibleTopMargin = 1 << 3,
UIViewAutoresizingFlexibleHeight = 1 << 4,
UIViewAutoresizingFlexibleBottomMargin = 1 << 5
};
以上代碼等價于
6.枚舉用在switch語句里思币,最好不要有default分支。
第6條:理解屬性這一概念
1.在OC中羡微,把實例變量當做一種存儲偏移量所用的“特殊變量”支救,交由“類對象”保管。偏移量會在運行期查找拷淘,如果類的定義變了,那么存儲的偏移量也就變了指孤,這樣的話启涯,無論何時訪問實例變量,總能使用正確的偏移量恃轩。
2.@synthesize和@dynamic
@implementation EOCPerson
@synthesize firstName = _myFirstName;
@synthesize lastName = _myLastName;
@end
上述語法會將生成的實例變量名為為_myFirstName與_myLastName,而不再使用默認的名字结洼。
使用@dynamic關(guān)鍵字,它會告訴編譯器:不要自動創(chuàng)建實現(xiàn)屬性所用的實例變量叉跛,也不要為其創(chuàng)建存取方法松忍。而且,在編譯訪問屬性的代碼時筷厘,即使編譯器發(fā)現(xiàn)沒有定義存取方法鸣峭,也不會報錯,它相信這些方法能在運行期找到酥艳。
3.具備readonly屬性的屬性僅擁有獲取方法,只有當改屬性由@synthesize實現(xiàn)時,編譯器才會為其合成獲取方法幢竹。你可以用此特質(zhì)把某個屬性對外公開為只讀屬性峻厚,然后在“class-continuation分類”中將其重新定義為讀寫屬性。
4.內(nèi)存管理語義
- assign “設(shè)置方法”只會執(zhí)行針對“純量類型”(scalar type骤铃,例如CGFloat或NSInteger等)的簡單賦值操作拉岁。
- strong 此特質(zhì)表明該屬性定義了一種“擁有關(guān)系”。為這種屬性設(shè)置新值時惰爬,設(shè)置方法會先保留新值喊暖,并釋放舊值,然后再將新值設(shè)置上去补鼻。
- weak 此特質(zhì)表明該屬性定義了一種“非擁有關(guān)系”哄啄。為這種屬性賦新值時雅任,設(shè)置方法既不保留新值,也不釋放舊值咨跌。此特質(zhì)同assign類似沪么,然而在屬性所指的對象遭到摧毀時,屬性值也會清空锌半。
- unsafe_unretained 此特質(zhì)的語義和assign相同禽车,但是它適用于“對象類型”,該特質(zhì)表達一種“非擁有關(guān)系”刊殉,當目標對象遭到摧毀時殉摔,屬性值不會自動清空,這一點與weak有區(qū)別记焊。
- copy 此特質(zhì)所表達的所屬關(guān)系與strong類似逸月,然而設(shè)置方法并不保留新值,而是將其“拷貝”遍膜。只要實現(xiàn)屬性所用的對象是“可變的”碗硬,就應該在設(shè)置新屬性值時拷貝一份。
第7條:在對象內(nèi)部盡量直接訪問實例變量
在寫入實例變量時瓢颅,通過其設(shè)置方法來做恩尾,而在讀取實例變量時,則直接訪問之挽懦。此辦法既能提高讀取操作的速度翰意,又能控制對屬性的寫入操作。