Objective-C與Foundation
對(duì)象(Object)
對(duì)象和結(jié)構(gòu)的不同之處在于:
1.對(duì)象還可以包含一組函數(shù),并且這些函數(shù)可以使用對(duì)象所保存的數(shù)據(jù)。這類函數(shù)稱為方法。
2.結(jié)構(gòu)中的數(shù)據(jù)稱為成員,對(duì)象中的數(shù)據(jù)稱為實(shí)例變量(instance variables)。
類(Classes)
一個(gè)類定義了一種對(duì)象,同時(shí)它也可以創(chuàng)建這種對(duì)象。類既是對(duì)象的原型,又是生產(chǎn)對(duì)象的工廠。
關(guān)于對(duì)象圖(object diagrams)的注意事項(xiàng):
類一般都使用虛線來(lái)畫。實(shí)例一般使用實(shí)線畫。
創(chuàng)建對(duì)象并使用對(duì)象(Creating and using your first object)
#import和#include的區(qū)別:
-
import指令導(dǎo)入更有效率。導(dǎo)入之前會(huì)讓編輯器檢查之前是否已經(jīng)導(dǎo)入過這個(gè)文件,或是已經(jīng)被包含到目標(biāo)文件中了。
-
include指令只能告訴編譯器做簡(jiǎn)單的復(fù)制。
消息的接收方是一個(gè)指向接收消息的對(duì)象的地址。 方法執(zhí)行后,類會(huì)在堆上給實(shí)例聲明一部分內(nèi)存,然后返回新對(duì)象的地址。
用最少的代碼獲取一個(gè)類的實(shí)例,這種方法稱為便利方法(convenience method)。
NSArray
使用快速枚舉遍歷NSMutableArray時(shí),不能在枚舉過程中增加或刪除數(shù)組中的指針。如果遍歷時(shí)需要添加或刪除指針,則需要使用標(biāo)準(zhǔn)的for循環(huán)。
用arrayWithObjects: 方法創(chuàng)建數(shù)組時(shí),末尾應(yīng)添加nil,否則會(huì)崩潰
方括號(hào)的三種使用情形:
- 發(fā)送消息
- 創(chuàng)建NSArray對(duì)象:NSArray *dateList = @[now, yesterday, tomorrow];
- 訪問某個(gè)數(shù)組特定索引上的對(duì)象:NSDate *firstDate = dateList[0];
有時(shí)在代碼中,這些不同的使用方法會(huì)疊加起來(lái)。發(fā)生這種情況的時(shí)候,使用舊式的數(shù)組方法會(huì)讓代碼更容易閱讀。
id selectedDog = dogs[[tableView selectedRow]];
舊式:
id selectedDog = [dogs objectAtIndex:[tableView selectedRow]];
類前綴
OC沒有命名空間,因此,為了避免名字沖突,蘋果公司推薦使用三個(gè)或三個(gè)以上的字母作為類的前綴,讓類的名字獨(dú)一無(wú)二。
繼承
繼承層次
NSObject雖然有很多方法,但是只有一個(gè)實(shí)例變量:isa指針。任何一個(gè)對(duì)象的isa指針都會(huì)指向創(chuàng)建該對(duì)象的類。(isa == is a “是一個(gè)”)
description方法和%@轉(zhuǎn)換說明
格式說明符%@讓對(duì)象描述自己。處理%@時(shí),程序會(huì)先向相應(yīng)的指針變量所指的對(duì)象發(fā)送description消息。
description返回該對(duì)象的內(nèi)存地址。
對(duì)象實(shí)例變量及屬性
對(duì)象實(shí)例變量是指向另一個(gè)對(duì)象的指針。
一對(duì)一關(guān)系
指針,指向單個(gè)復(fù)雜的對(duì)象。建議每次都聲明屬性,這樣就不需要自己創(chuàng)建存取方法。一對(duì)多關(guān)系
指針,指向某個(gè)collection類的實(shí)例。需要自己創(chuàng)建實(shí)例變量,存取方法及從關(guān)系中增加或移除對(duì)象的方法。
任何一個(gè)對(duì)象不會(huì)在其內(nèi)部保存其他對(duì)象,只會(huì)保存相應(yīng)對(duì)象的地址。
**** 指向其他對(duì)象的特性會(huì)產(chǎn)生兩大副作用:
- 單個(gè)對(duì)象可能會(huì)扮演多個(gè)角色。
-
導(dǎo)致產(chǎn)生大量獨(dú)立的對(duì)象,耗盡程序的可用內(nèi)存。
對(duì)象所有權(quán)與ARC
Objective-C提出了對(duì)象所有權(quán)(object ownership)概念。任何一個(gè)對(duì)象都知道自己當(dāng)前有多少個(gè)擁有方。
- 當(dāng)collection對(duì)象加入某個(gè)對(duì)象時(shí),會(huì)保存指向該對(duì)象的指針,并成為該對(duì)象的擁有方。
- 當(dāng)collection對(duì)象移除某個(gè)對(duì)象時(shí),會(huì)刪除指向該對(duì)象的指針,并不再是該對(duì)象的擁有方。
使用@class編譯器不會(huì)查看實(shí)現(xiàn)細(xì)節(jié),所以處理速度更快。
內(nèi)存泄漏
如果程序有用不到的但又沒有釋放的對(duì)象,就稱程序有內(nèi)存泄漏(memory leak)。通常情況下,內(nèi)存泄漏會(huì)導(dǎo)致程序中不使用的對(duì)象越來(lái)越多,從而占用越來(lái)越多的內(nèi)存。
類擴(kuò)展(class extensions)
頭文件是類聲明它的屬性及方法的地方這樣其他的對(duì)象才能夠知道如何和類進(jìn)行交互。
然而,不是所有的屬性或方法都需要在類的頭文件中聲明。有的屬性或方法只是該類或其類實(shí)例才需要使用的。設(shè)計(jì)實(shí)現(xiàn)細(xì)節(jié)的屬性或方法最好在類擴(kuò)展中聲明。類擴(kuò)展是一組私有的聲明。只有類和其實(shí)例才能使用在類擴(kuò)展中聲明的屬性,實(shí)例變量,方法。
將聲明移到類擴(kuò)展中有兩個(gè)相關(guān)的影響
- 非本類對(duì)象不能再看到這個(gè)屬性。(無(wú)法獲取到)
- 使類的頭文件聲明減少。頭文件其實(shí)是一個(gè)告示牌,它的工作就是告訴其他開發(fā)者如何使用這個(gè)類。而太多的內(nèi)容會(huì)給閱讀和使用增加困難。
隱藏可變屬性(hiding mutability)
例如在.h文件中聲明@property (nonatomic) NSMutable *array不可變屬性。在類擴(kuò)展中聲明可變實(shí)例變量:NSMutableArray *_array;
如此以來(lái),非本類對(duì)象只知道其為不可變數(shù)組。實(shí)際上是可變的實(shí)例。
頭文件與繼承(headers and inheritance)
子類無(wú)法獲取父類的類擴(kuò)展。
避免內(nèi)存泄漏(preventing memory leaks)
強(qiáng)引用會(huì)保留對(duì)象的擁有方,使其不被釋放。而弱引用則不會(huì)保留。
如果需要明確的將指針聲明為弱引用,則可以標(biāo)注__weak,類似以下代碼:
__weak NSString *str;
深入學(xué)習(xí):手動(dòng)引用計(jì)數(shù)和ARC歷史
Retain計(jì)數(shù)規(guī)則
- 如果用來(lái)創(chuàng)建對(duì)象的方法,其方法名是以alloc或new開頭的,或者包含copy,mutableCopy,那么便得到的該對(duì)象的所有權(quán)(即可以假設(shè)新對(duì)象的retain計(jì)數(shù)是1,而且該對(duì)象不會(huì)在NSAutoreleasePool對(duì)象中)。
- 通過任何其他途徑創(chuàng)建的對(duì)象(例如通過便捷方法),你是沒有所有權(quán)的(即可以假設(shè)新對(duì)象的retain計(jì)數(shù)是1,而且該對(duì)象已經(jīng)在NSAutoreleasePool中。如果沒有保留該對(duì)象,那么當(dāng)NSAutoreleasePool對(duì)象被“排干”(drain)時(shí),這個(gè)對(duì)象就會(huì)被釋放。)
- 如果你不擁有某個(gè)對(duì)象,但是要確保該對(duì)象能繼續(xù)存在,那么可以通過向其發(fā)送retain消息來(lái)獲得所有權(quán)。
- 當(dāng)你擁有的某個(gè)對(duì)象不需要使用時(shí),可以向其發(fā)送release或者autorelease。
理解內(nèi)存管理的技巧之一是“從局部的角度來(lái)考慮問題,以類為分解”。
Collection類(collection classes)
NSSet對(duì)象最大用處是檢查某個(gè)對(duì)象是否存在。完成此類任務(wù)NSSet對(duì)象的速度比數(shù)組快得多。
NSSet對(duì)象中的對(duì)象是無(wú)序的,所以不能通過索引來(lái)訪問。只能向NSSet對(duì)象查詢某個(gè)對(duì)象是否存在。
NSObject類定義了一個(gè)名為isEqual:的方法。用來(lái)檢查兩個(gè)對(duì)象是否相等。
- 相等(equal)和相同(identical)是兩個(gè)概念。
- 相同的變量一定是相等的,相等的變量不一定相同。
不可修改對(duì)象(immutable objects)
使用不可修改的collection可以節(jié)約內(nèi)存提高性能,因?yàn)樗肋h(yuǎn)無(wú)需拷貝。
使用可修改的對(duì)象,則可能發(fā)生一種情況:程序中的其他代碼可能在你使用這個(gè)可修改的對(duì)象的時(shí)候修改它的內(nèi)容。為避免這種情況,就需要copy一份。
使用不可修改的collection,例如NSArray的copy方法其時(shí)不會(huì)做任何額外的工作,僅僅返回指向自身的指針。而NSMutableArray的copy方法會(huì)制作一份自己的拷貝,并返回指向新數(shù)組對(duì)象的指針。
數(shù)組排序(sorting arrays)
NSMutableArray 最常用的一個(gè)排序方法:
- (void)sortUsingDescriptors:(NSArray *)sortDescriptors;
該方法的實(shí)參是一個(gè)包含NSSortDescriptor對(duì)象的數(shù)組對(duì)象,排序描述對(duì)象包含兩個(gè)信息,一是數(shù)組中對(duì)象的屬性名,二是升序還是降序。
用于排序的屬性可以是任意的實(shí)例變量,也可以是實(shí)例方法的返回值。
過濾(filtering)
對(duì)collection進(jìn)行過濾的時(shí)候,程序?qū)?duì)collection對(duì)象和一條邏輯語(yǔ)句進(jìn)行比較,得到一個(gè)合成的collection,這個(gè)collection只包含滿足這條語(yǔ)句的對(duì)象。
- NSPredicate對(duì)象
詳情參考《Predicate Programming Guide》
事例:
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"過濾條件"];
NSArray *array = [allAssets filteredArrayUsingPredicate:predicate];
C語(yǔ)言基本類型
collection只能保存對(duì)象,如果要保存float,int等變量,需要進(jìn)行封裝。
NSNumber封裝的值不能用來(lái)計(jì)算,只能先提取出來(lái),再做計(jì)算。
結(jié)構(gòu)體用NSValue封裝。
Collection與nil
本章所介紹的collection對(duì)象都不能保存nil。如果要將“空洞”加入collection,可以使用NSNull類。例如:
[hotel addObject:lobby];
[hotel addObject:[NSNull null]];
[hotel addObject:pool];
常量(constants)
在Objective-C中,通??梢酝ㄟ^兩種途徑來(lái)定義常量。即#define和全局變量。
預(yù)處理指令(Preprocessor directives)
C,C++,OC 代碼文件需要經(jīng)過兩步才能完成編譯:
- 首先預(yù)處理器會(huì)讀入并處理整個(gè)文件。
- 接著,預(yù)處理器的輸出結(jié)果會(huì)作為輸入交給真正的編譯器。預(yù)處理指令以#開頭。
指定導(dǎo)入文件時(shí),需要為文件名加上雙引號(hào)或尖括號(hào)。如果是雙引號(hào),那么編譯器會(huì)先在項(xiàng)目目錄下查找相應(yīng)的頭文件。如果是尖括號(hào),那么編譯器會(huì)先在預(yù)先設(shè)定好的標(biāo)準(zhǔn)目錄下查找相應(yīng)的頭文件。
為了簡(jiǎn)化文件導(dǎo)入代碼并加快編譯速度,Xcode加入了對(duì)預(yù)編譯文件的支持,凡是出現(xiàn)在預(yù)編譯文件中的頭文件,Xcode都會(huì)事前編譯好并自動(dòng)導(dǎo)入每個(gè)文件。
通過#define,不僅可以替換代碼中的某個(gè)特定的值,還可以構(gòu)建類似函數(shù)的代碼段,后者的這種代碼段稱為宏(macro)。
全局變量(global variables)
編寫Objective-C時(shí),通常不是使用#define來(lái)保存常量,而是使用全局變量來(lái)完成這項(xiàng)任務(wù)。
enum
為某個(gè)方法的形參聲明某個(gè)特定的類型,并告訴編譯器,調(diào)用方只能向該方法傳入枚舉類型中的一種。
通常情況下,枚舉常量所代表的數(shù)字不會(huì)有實(shí)際的意義,其作用僅僅是為了能夠區(qū)分不同的常量。
從OS X10.8 和 iOS6系統(tǒng)開始,蘋果公司引入了一種新的enum聲明語(yǔ)法:
NS_ENUM()。示例如下:
typedef NS_ENUM(int, Speed) {
BlenderS1,
BlenderS2
};
NS_ENUM()實(shí)際上是一個(gè)預(yù)處理器宏,它帶有兩個(gè)實(shí)參:數(shù)據(jù)類型和名字。
蘋果公司使用NS_ENUM()做enum聲明,最重要的優(yōu)點(diǎn)是它可以聲明整數(shù)的數(shù)據(jù)類型(short,unsigned,long等)。與舊語(yǔ)法相比,可以節(jié)省內(nèi)存。
比較#define與全局變量
- 在某些情況下,使用全局變量的效率更高。例如,如果某個(gè)字符串都以一個(gè)固定的全局變量的形式出現(xiàn),那么在進(jìn)行字符串比較時(shí),就可以使用==,而不是isEqual:(算術(shù)運(yùn)算快于消息發(fā)送)。
- 調(diào)試程序時(shí),全局變量可以在調(diào)試器中查看其值。
通過NSString 和 NSData 將數(shù)據(jù)寫入文件(writing files with NSString and NSData)
在將字符串對(duì)象寫入文件時(shí),要指定字符串編碼。字符串編碼的作用是描述字符和代表字符的數(shù)字之間的映射關(guān)系。
文件的路徑可以是絕對(duì)的或相對(duì)的。絕對(duì)路徑以“/”開頭(/代表文件系統(tǒng)的根目錄)。而相對(duì)路徑則是相對(duì)于程序當(dāng)前的工作目錄。編寫程序時(shí),通常都會(huì)使用絕對(duì)路徑。
NSData對(duì)象“代表”內(nèi)存中的某塊緩沖區(qū)。可以保存相應(yīng)字節(jié)數(shù)的數(shù)據(jù)。
回調(diào)(callbacks)
回調(diào)就是將一段可執(zhí)行的代碼和一個(gè)特定的事件綁定起來(lái)。當(dāng)特定的事件發(fā)生時(shí),就會(huì)執(zhí)行這段代碼。
在OC中,有四種途徑可以實(shí)現(xiàn)回調(diào):
- 目標(biāo)-動(dòng)作對(duì)(target-action)
- 輔助對(duì)象(helper objects)
- 通知(notifications)
- Block對(duì)象(Blocks)
運(yùn)行循環(huán)(the run loop)
事件驅(qū)動(dòng)的程序需要有一個(gè)對(duì)象,專門負(fù)責(zé)等待事件的發(fā)生。NSRunLoop實(shí)例會(huì)持續(xù)等待著,當(dāng)特定的事件發(fā)生時(shí),就會(huì)向相應(yīng)的對(duì)象發(fā)送消息。NSRunLoop實(shí)例會(huì)在特定的事件發(fā)生時(shí)觸發(fā)回調(diào)。
[[NSRunLoop currentRunLoop] run];
沒有使用的變量可以使用__unused 來(lái)消除警告。
目前的回調(diào)規(guī)則如下:
當(dāng)要向一個(gè)對(duì)象發(fā)送一個(gè)回調(diào)時(shí),蘋果公司會(huì)使用目標(biāo)-動(dòng)作對(duì)。
當(dāng)要向一個(gè)對(duì)象發(fā)送多個(gè)回調(diào)時(shí),使用相應(yīng)協(xié)議的輔助對(duì)象。
回調(diào)與對(duì)象所有權(quán)
遵守以下規(guī)則:
- 通知中心不擁有觀察者
- (void)dealloc {
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
- 對(duì)象不擁有委托對(duì)象或數(shù)據(jù)源對(duì)象
- (void)dealloc {
[... setDelegate:nil];
[... setDataSource:nil];
}
- 對(duì)象不擁有目標(biāo)
[... setTarget:nil];
選擇器的工作機(jī)制
當(dāng)某個(gè)對(duì)象收到消息時(shí),會(huì)對(duì)該對(duì)象的類進(jìn)行查詢。
方法查詢速度非??臁H绻褂梅椒ǖ膶?shí)際名稱進(jìn)行查詢,那么查詢速度會(huì)很慢。為了提速,編譯器會(huì)為每個(gè)其接觸過的方法附一個(gè)唯一的數(shù)字。運(yùn)行時(shí),程序使用這個(gè)數(shù)字進(jìn)行查找。
以上提到的代表特定方法名的唯一數(shù)字稱為選擇器(selector)。當(dāng)一個(gè)方法需要一個(gè)選擇器作為實(shí)參,它實(shí)際上就是需要這個(gè)數(shù)字。通過編譯指令@selector,可以得到與方法名相對(duì)應(yīng)的選擇器。
Block對(duì)象
與函數(shù)指針相比,如果能正確的使用block對(duì)象,就可以寫出更簡(jiǎn)介的代碼。
Block對(duì)象VS其他回調(diào)
委托機(jī)制和通告機(jī)制有一個(gè)缺點(diǎn),即回調(diào)的設(shè)置代碼和回調(diào)方法的具體實(shí)現(xiàn)無(wú)法寫在同一段代碼中。而且兩段代碼通常會(huì)相隔很遠(yuǎn)。
深入學(xué)習(xí)Block對(duì)象
在block外的變量稱為外部變量,當(dāng)執(zhí)行block對(duì)象時(shí),為了確保其下的外部變量能夠始終存在,相應(yīng)地block對(duì)象會(huì)捕獲這些變量。
對(duì)于基本類型的變量,捕獲意味著程序會(huì)拷貝變量的值,并用block對(duì)象內(nèi)的局部變量保存。對(duì)指針類型的變量,block會(huì)使用強(qiáng)引用。
在Block中使用self
myBlock = ^{
NSLog(@"Employee:%@", self);
}
Employee有一個(gè)指向Block對(duì)象的指針。這個(gè)block對(duì)象會(huì)捕獲self,所以它有一個(gè)指回Employee的指針。陷入強(qiáng)引用循環(huán)。
為打破強(qiáng)引用,應(yīng)該如此:
__weak Employee *weakSelf = self;
myBlock = ^{
Employee *innerSelf = weakSelf;
NSLog(@"Employee:%@", self);
}
在Block中無(wú)意使用self
如果直接在Block對(duì)象中使用實(shí)例變量,那么block會(huì)捕獲self。而不會(huì)捕獲實(shí)例變量。
init
每個(gè)類都有一個(gè)指定初始化方法。如:init是NSObject的指定初始化方法。
指定初始化方法扮演的是單一入口的角色。任何類都有且只有一個(gè)指定初始化方法。如果某個(gè)類還有其它初始化方法,那么這些方法應(yīng)該(直接或間接)調(diào)用指定初始化方法。
編寫指定初始化方法時(shí),應(yīng)該遵循以下規(guī)則:
- 其他的初始化方法都應(yīng)該直接或間接的調(diào)用指定初始化方法。
- 指定初始化方法應(yīng)該先調(diào)用父類的指定初始化方法,然后再對(duì)變量進(jìn)行初始化。
- 如果某個(gè)類的指定初始化方法和父類的不同(這里指方法名不同),就必須覆蓋父類的指定初始化方法,并調(diào)用新的指定初始化方法。
- 如果某個(gè)類有多個(gè)初始化方法,就應(yīng)該在相應(yīng)的頭文件中明確的標(biāo)明哪個(gè)方法是指定初始化方法。
禁用init方法
最佳解決方案是覆蓋父類的指定初始化方法,然后通過某種途徑告之程序員不能調(diào)用這個(gè)方法,并提供修改建議:
- (instancetype)init {
[NSException raise:@"CZWallSafeInitialization"
format:@"USE initWithSecretCode:, not init"];
}
再談屬性
深復(fù)制與淺復(fù)制
- copy復(fù)制后的對(duì)象是不可變的,mutableCopy復(fù)制后的對(duì)象是可變的。與原始對(duì)象是否可變無(wú)關(guān)。
- 對(duì)不可變對(duì)象進(jìn)行copy是淺復(fù)制,mutableCopy是深復(fù)制。
- 對(duì)可變對(duì)象進(jìn)行copy和mutableCopy都是深復(fù)制。
針對(duì)容器類對(duì)象的深復(fù)制與淺復(fù)制(只探討復(fù)制后容器內(nèi)元素的變化)
- 容器內(nèi)對(duì)象淺復(fù)制: 方法: copy,mutableCopy,initWithArray: withItems:NO
- 容器內(nèi)對(duì)象深復(fù)制: 方法: 歸檔,initWithArray: withItems:YES (如容器內(nèi)對(duì)象也是容器對(duì)象,則子類容器對(duì)象是使用init方法是淺復(fù)制。使用歸檔方法是完全的深復(fù)制)
KVC (Key-value coding)
KVC能夠讓程序通過名稱直接存取屬性,因?yàn)榕cKVC有關(guān)的方法都是在NSObject中定義的,所以凡是繼承自NSObject的類都具備KVC功能。
[a setProductName:@“Washing Machine”];
現(xiàn)在用KVC重寫:
[a setValue@“Washing Machine” forKey:@“productName”];
setValue: forKey:方法會(huì)查找名為 setProductName:的存方法,如果a對(duì)象沒有setProductName:方法,就會(huì)直接為實(shí)例變量賦值。
也可以使用KVC讀取實(shí)例變量
[a valueForKey:@“productName”];
為什么使用KVC,有什么好處?
- 當(dāng)蘋果公司提供的某個(gè)框架需要向你編寫的對(duì)象寫入數(shù)據(jù)時(shí),會(huì)使用setValve:forKey:
- 當(dāng)蘋果公司提供的某個(gè)框架需要從你編寫的對(duì)象讀取數(shù)據(jù)時(shí),會(huì)使用valveForKey:
所謂對(duì)象封裝是指對(duì)象的方法可以公開,但是實(shí)例變量應(yīng)該保持私有。KVC是一個(gè)例外。
非對(duì)象類型
KVC只對(duì)對(duì)象有效,但是可以將要賦值的int,float等類型轉(zhuǎn)化為NSNumber對(duì)象。
Key路徑
當(dāng)遍歷一個(gè)特別長(zhǎng)的屬性表的時(shí)候可以使用Key path。將想要的key排成一個(gè)長(zhǎng)串,用逗號(hào)分隔。
KVO
鍵值觀察是指當(dāng)指定的屬性被修改時(shí),允許對(duì)象接收通知的機(jī)制??偟膩?lái)說就是告訴一個(gè)對(duì)象,“我要觀察你的某個(gè)屬性,如果他發(fā)生了變化,就通知我”。
在KVO中使用context
在代碼中將某個(gè)對(duì)象注冊(cè)為觀察者時(shí),需要傳遞指針作為context。當(dāng)接收變化的通知時(shí),context會(huì)隨通知一起發(fā)送。context可以用來(lái)回答“這真的是我需要的通知嗎”
顯式觸發(fā)通知
如果不使用存取方法設(shè)置屬性,觀察這便不會(huì)收到通知。因此應(yīng)在屬性被賦值的前后添加如下代碼:
[self willChangeValueForKey:@“某屬性”];
...;
[self didChangeValueForKey:@“某屬性”];
獨(dú)立的屬性
_lastTime屬性的值發(fā)生變化時(shí),_lastTimeString也會(huì)發(fā)生變化時(shí),當(dāng)你想觀察_lastTimeString時(shí)會(huì)發(fā)現(xiàn)觀察者并沒有正確的收到通知。為了修復(fù)這個(gè)問題,應(yīng)在被觀察者的.m文件中實(shí)現(xiàn)一個(gè)類方法來(lái)做這項(xiàng)工作。
+ (NSSet *)keyPathsForValuesAffectingLastTimeString {
return [NSSet setWithObject:@“l(fā)astTime”];
}
注意這個(gè)方法的命名:
它是keyPathsForValuesAffecting加上首字母大寫的鍵的名字。
沒有必要在.h中聲明這個(gè)方法,系統(tǒng)會(huì)在運(yùn)行時(shí)找到它。
范疇
應(yīng)該使用范疇來(lái)給已經(jīng)存在的類增加新方法,而不是在范疇中替換已存在的方法,這種情況下應(yīng)該創(chuàng)建子類。
在定義方法名時(shí)加上前綴(cz_)
位運(yùn)算
和內(nèi)存打交道時(shí),無(wú)法精確到位,必須以字節(jié)為單位。
編寫代碼時(shí)為了方便確認(rèn),會(huì)在十六進(jìn)制前加上前綴0x
需要使用按位或的運(yùn)算
使用整數(shù)來(lái)保存某個(gè)設(shè)置的特定狀態(tài),因?yàn)檎麛?shù)是由一系列的位組成,所以可以使用整數(shù)中的某個(gè)位來(lái)表示設(shè)置的某個(gè)狀態(tài)時(shí)打開的還是關(guān)閉的(只有與狀態(tài)相對(duì)應(yīng)的那個(gè)位是1,其余是0)。
同樣的還有按位與,編程時(shí),可以通過按位與運(yùn)算檢查某個(gè)整數(shù)是否包含指定的標(biāo)志位。
C字符串和NSString對(duì)象的相互轉(zhuǎn)化
char *greeting = "Hello";
NSString *x = [NSString stringWithCString:greeting encoding:NSUTF8StringEncoding];
NSString *greeting = @"Hello";
const char *x = NULL;
if ([greeting canBeConvertedToEncoding:NSUTF8StringEncoding]) {
x = [greeting cStringEncoding:NSUTF8StringEncoding];
}