iOS面試攻略上篇:Objective-C關(guān)鍵字和概念
歡迎查看下篇:iOS面試攻略下篇:Objective-C面試題和基本概念
@
看到這個(gè)關(guān)鍵字,我們就應(yīng)該想到,這是Object-C對(duì)C語言的擴(kuò)展,例如@interface XXX。
@interface
聲明類
@implementation
實(shí)現(xiàn)類
@protocol
聲明協(xié)議
@optional
與@protocol配合使用,說明協(xié)議中的某個(gè)或者某幾個(gè)方法可以不實(shí)現(xiàn)
@required
與@protocol配合使用,說明協(xié)議中的某個(gè)方法或者某幾個(gè)方法必須實(shí)現(xiàn)
@end
與@interface ,@implementation,@protocol配合使用,代表聲明或者實(shí)現(xiàn)結(jié)束
@encode
@encode為編譯器宏,它可以將類型轉(zhuǎn)換為相應(yīng)的字符串。
id
id是指向Objective-C類對(duì)象的指針,它可以聲明為任何類對(duì)象的指針,當(dāng)在Objective-C中使用id時(shí),編譯器會(huì)假定你知道,id指向哪個(gè)類的對(duì)象。與void*是不同的是,void*編譯器不知道也不假定指向任何類型的指針。
nil
定義為一個(gè)常量,如果一個(gè)指針的值為nil,代表這個(gè)指針沒有指向任何對(duì)象。
self
在Objective-C中,關(guān)鍵字self與c++中this是同一概念,就是類對(duì)象自身的地址,通過self可以調(diào)用自己的實(shí)例變量和方法
Super
當(dāng)子類需要調(diào)用父類的方法時(shí),會(huì)用到Super關(guān)鍵字. Super指向的是父類的指針,子類重寫父類的方法時(shí),調(diào)用父類的方法是一個(gè)比較好的習(xí) 慣。因?yàn)?當(dāng)我們不知道父類在該方法中實(shí)現(xiàn)的功能時(shí),如果不調(diào)用父類的方法,有可能我們重寫的方法會(huì)失去該功能,這是我們不愿意看到的情況。
NSNull
NSNull是沒有的意思,如果一個(gè)字典的值為NSNull,那說明與該值對(duì)應(yīng)的Key是沒有值的,例如Key為address,說明與address對(duì)應(yīng)的是值是沒有。
self super class public protected private id
[self class] [super class] selector
objective-c runtime reference
標(biāo)準(zhǔn)用法
self = [super init]
new
1 Objective-C有一個(gè)特性,就是可以把類當(dāng)成對(duì)象來發(fā)送消息,這種用法通常用于新建對(duì)像時(shí),例如 XXX *object = [XXX new];
類方法 +
如果想聲明屬于類而不屬于類對(duì)象的方法,用+。+用來修飾類的方法,使用+修飾的類方法,是整個(gè)類的方法,不屬于哪一個(gè)類對(duì)象,這與C++中的static在類中使用的概念一樣,
%@
在NSLog中,使用%@表示要調(diào)用對(duì)象的description方法。
概念
類
是一種結(jié)構(gòu),它表示對(duì)象的類型,就像int與 char 一樣,也可以聲明類的變量(對(duì)像)
實(shí)例化
為類的對(duì)象分配內(nèi)存和初始化,達(dá)到可以使用該 類對(duì)象的目的。
對(duì)象(實(shí)例)
類的實(shí)例化后的產(chǎn)物
消息
在Object-C中,類的對(duì)象執(zhí)行的操作,是通過給該類或者該類對(duì)象發(fā)送消息實(shí)現(xiàn),如:[object func];就是給object對(duì)象發(fā)送 func消息,類似C++中的方法調(diào)用。給object對(duì)象發(fā)送func消息后,object對(duì)象查詢所屬類的func方法執(zhí)行。
方法調(diào)度
當(dāng)向一個(gè)對(duì)象發(fā)送消息時(shí)(調(diào)用方法),這個(gè)方法是怎么被調(diào)用的呢?這就依賴于方法高度程序,方法調(diào)度程序查找的方法如下:
在本類的方法中,找被調(diào)用的方法,如果找到了,就調(diào)用,如果找不到被沿著繼承路徑去查找,從哪個(gè)類找到,就調(diào)用哪個(gè)類的方法,如果到最根上的類還是沒有找到,那編譯就會(huì)出錯(cuò)。
繼承與復(fù)合
在Objective-C中支持繼承,但只是支持單一繼承(有且只有一個(gè)父類有),如果想使用多繼承的特性,可以使用分類和協(xié)議技術(shù)。
繼承是is-a,復(fù)合是has-a。復(fù)合是通過包含指向?qū)ο蟮闹羔槍?shí)現(xiàn)的,嚴(yán)格意義上講,復(fù)合是針對(duì)于對(duì)象間來說,對(duì)于基本數(shù)據(jù)類型來說,它們被認(rèn)為是對(duì)象的一部分。
裝箱與拆箱
由于NSArray,NSDirectory等類不能直接存儲(chǔ)基本數(shù)據(jù)類型,所以要想在NSArray\NSDirectory中使用基本數(shù)據(jù)類型,就得使用裝箱與拆箱。
在Objective-C中,可以使用NSNumber和NSValue來實(shí)現(xiàn)對(duì)數(shù)據(jù)類型的包裝,NSNumber可以實(shí)現(xiàn)對(duì)基本數(shù)據(jù)類型的包裝,NSValue可以實(shí)現(xiàn)對(duì)任意類型數(shù)據(jù)的包裝。
將基本類型封裝成對(duì)象叫裝箱,從封裝的對(duì)象中提取基本類型叫拆箱(取消裝箱),其它語言如Java原生支持裝箱與拆箱,Ojbective-C不支持自動(dòng)裝箱與拆箱,如果需要得需要自己來實(shí)現(xiàn)裝箱與拆箱。
存取方法
在使用類對(duì)象的實(shí)例變量(成員數(shù)據(jù))時(shí),不要直接使用對(duì)象中的實(shí)例,要使用存以方法來獲取或者修改實(shí)例,既setter和getter,在 Cocoa中, 存取方法有命名習(xí)慣,我們得符合這種習(xí)慣,以便于與其它團(tuán)隊(duì)成員合作。setter方法是修改或者設(shè)置實(shí)例值,命名習(xí)慣為set+實(shí)例名,例有一個(gè)類有 path實(shí)例變量,那setter命名為setPath,getter命名為Path,為什么不是getPath,因?yàn)間et在Cocoa中有特殊的含 義,這個(gè)含義就是帶有g(shù)et的方法就意味著這個(gè)方法通過形參指針(傳入函數(shù)的參數(shù)指針)來返回值。我們要遵守這個(gè)命名習(xí)慣或者說規(guī)則。
在Objective-C 2.0中加入了@property和@synthesize來代替setter和getter,這兩個(gè)關(guān)鍵字為編譯器指令。還有點(diǎn)表達(dá)式,存取類成員的值時(shí),可以使用點(diǎn)表達(dá)式。
Object.attribute,當(dāng)點(diǎn)表達(dá)式在=號(hào)左邊時(shí),調(diào)用的是setter方法,在=號(hào)右邊時(shí),調(diào)用的是getter方法。
@property 語法為:@property (參數(shù)) 類型 變量名.
在這里主要說明一下參數(shù).
參數(shù)分為三種:
***種:讀寫屬性包括(readonly/readwrite/)
第二種:setter屬性(assign,copy,retain),assign是簡(jiǎn)單的賦值,copy是釋放舊成員變量,并新分配內(nèi)存地址給成 員 變量,將傳入?yún)?shù)內(nèi)容復(fù)制一份,給成員變量。retain是將傳入 參數(shù)引用計(jì)數(shù)加1,然后將原有的成員變量釋放,在將成員變量指向該傳入?yún)?shù)。
第三種:與多線程有關(guān)(atomic,nonatomic).當(dāng)使用多線程時(shí),使用atomic,在不使用多線程時(shí)使用nonatomic
對(duì)象創(chuàng)建與初始化
在Objective-C中創(chuàng)建對(duì)象有兩種方法,一種是[類 new];另一種是[[類 alloc] init],這兩種方法是等價(jià)的,但按慣例來講,使用[[類 alloc] init];
alloc操作是為對(duì)象分配內(nèi)存空間,并將對(duì)象的數(shù)據(jù)成員都初始,int 為0,BOOL 為NO, float 為0.0等。
初始化,默認(rèn)的初始化函數(shù)為init,init返回值為id,為什么回返回id呢,因?yàn)橐獙?shí)現(xiàn)鏈?zhǔn)奖磉_(dá)式,在Objective-C中叫嵌套調(diào)用。
為什么要嵌套調(diào)用??因?yàn)槌跏蓟椒╥nit返回值可能與alloc返回的對(duì)象不是同一個(gè)?為什么會(huì)發(fā)生這種情況?基于類簇的初始化,因?yàn)閕nit可以接受參數(shù),在init內(nèi)部有可能根據(jù)不同的參數(shù)來返回不同種類型的對(duì)象,所以最會(huì)發(fā)生上面說的情況。
在初始化時(shí),建議使用if (self = [super init])
便利初始化
當(dāng)一個(gè)類需要根據(jù)不同的情況來初始化數(shù)據(jù)成員時(shí),就需要便利初始化函數(shù),與init初始化不同的是,便利初始化函數(shù)有參數(shù),參數(shù)個(gè)數(shù)可以有1到N個(gè),N是類數(shù)據(jù)成員個(gè)數(shù)。
指定初始化函數(shù):什么是指定初始化函數(shù)?在類中,某個(gè)初始化函數(shù)會(huì)被指定為指定的初始化函數(shù),確定指定初始化函數(shù)的規(guī)則是初始化函數(shù)中,參數(shù)最多的為指定初始化函數(shù),
其它未被指定為指定初始化函數(shù)的初始化函數(shù)要調(diào)用指定初始化函數(shù)來實(shí)現(xiàn)。對(duì)于該類的子類也是一樣,只要重寫或者直接使用父類的指定初始化函數(shù)。上述文字有些繞,來個(gè)例子吧
@interface A{
int x;
int y;
}
-(id) init;
-(id) initWithX:(int) xValue;
-(id) initWithY:(int) yValue;
-(id) initWithXY:(int) xValue
yVal:(int) yValue;
@end
這里initWithXY被確定為指定初始化函數(shù)。
-(id) initWithXY:(int) xValue
yVal:(int) yValue{
if (self = [super init]){
x = xValue;
y = yValue;
}
return self;
}
-(id) init{
if (self = self initWithXY:10
yVal:20){
}
return self;
}
.......
@interface B: A{
int z;
}
-(jd) initWithXY......;
@end
@implementation B
-(id) initWithXY:(int) xValue
yVal:(int) yValue{
if (self = [super initWithXY:10
yVal=20]){
z= 40;
}
return self;
}
@end
自動(dòng)釋放池
內(nèi)存管理是軟件代碼中的重中之重,內(nèi)存管理的好壞,直接影響著軟件的穩(wěn)定性。在Cocoa中,有自動(dòng)釋放池,這類似于C++中的智能指針。
NSObject有一個(gè)方法是autorelease,當(dāng)一個(gè)對(duì)象調(diào)用這個(gè)方法時(shí),就會(huì)將這個(gè)對(duì)象放入到自動(dòng)釋放池中。
drain,該方法是清空自動(dòng)釋放池,不是銷毀它。drain方法只適用于Mac OS X 10.4以上的版本,在我們寫的代碼中要使用release,release適用于所有版本。
自動(dòng)釋放池是以棧的方式實(shí)現(xiàn),當(dāng)創(chuàng)建一個(gè)自動(dòng)釋放池A時(shí),A被壓入棧頂,這時(shí)將接入autorelease消息的對(duì)象放入A自動(dòng)釋放池,這時(shí)創(chuàng)建一 個(gè)新的 B自動(dòng)釋放池,B被壓入棧頂,創(chuàng)建完成后刪除B,這個(gè)接收autorelease消息的對(duì)象依然存在,因?yàn)锳自動(dòng)釋放池依然存在。
引用計(jì)數(shù)
每個(gè)對(duì)象都有一個(gè)與之相應(yīng)的整數(shù),稱它為引用計(jì)數(shù),當(dāng)該引用計(jì)數(shù)為0時(shí),Objective-C自動(dòng)向該對(duì)象發(fā)送dealloc,以銷毀該對(duì)向,與該引用計(jì)數(shù)相關(guān)的方法(消息)有下面幾個(gè)
1 增加引用計(jì)數(shù):通過alloc,new,copy創(chuàng)建一個(gè)對(duì)象時(shí),該對(duì)象的引用計(jì)數(shù)加1(其實(shí)就是1,因?yàn)橹盀?)
2 增加引用計(jì)數(shù): retain
3 減少引用計(jì)數(shù): release
局部分配內(nèi)存(臨時(shí)對(duì)象):
1 如果使用alloc,new,copy創(chuàng)建對(duì)象,則需要主動(dòng)調(diào)用對(duì)象的release方法
2 如果使用非alloc,new,copy創(chuàng)建對(duì)象,我們認(rèn)為該對(duì)象引用計(jì)數(shù)為1,并已經(jīng)加入了自動(dòng)釋放池,我們不需要主動(dòng)的調(diào)用對(duì)象的release方法。
擁有對(duì)象(在類中以成員的方法存在):
1 如果使用alloc,new,copy創(chuàng)建對(duì)象,則需要在dealloc方法中,釋放該對(duì)象
2 如果使用非alloc,new,copy創(chuàng)建對(duì)象,則在擁有該對(duì)象時(shí),保留該對(duì)象(執(zhí)行retain方法),在dealloc方法中,釋放該對(duì)象。
dealloc
當(dāng)對(duì)象的引用計(jì)數(shù)為0時(shí),Objective-C會(huì)自動(dòng)發(fā)送對(duì)象的dealloc消息(自動(dòng)調(diào)用對(duì)象的dealloc方法,類似于C++的析構(gòu)函數(shù)),所以我們可以自己重寫dealloc方法,來實(shí)現(xiàn)類里的對(duì)其它使用資源的釋放工作。
注意:不要直接在代碼中顯示調(diào)用dealloc方法。
垃圾回收
在Objective-C 2.0中引入了垃圾回收機(jī)制(自動(dòng)管理內(nèi)存),在工程設(shè)置里設(shè)置Objective-C Garbage Collection為Required[-fobjc-gc-only]就可以使用垃圾回收機(jī)制。
啟用垃圾回收機(jī)制后,通常的內(nèi)存管理命令都變成了空操作指令,不執(zhí)行任何操作。
Objective-C的垃圾回收機(jī)制是一種繼承性的垃圾回收器,垃圾回收器定期檢查變量和對(duì)象以及他們之間的指針,當(dāng)發(fā)現(xiàn)沒有任何變量指向?qū)ο髸r(shí),就將該對(duì)象視為被丟棄的垃圾。所以在不在使用一個(gè)對(duì)象時(shí),將指針?biāo)闹羔樤O(shè)置為nil,這時(shí)垃圾回收器就會(huì)清理該對(duì)象。
注意:如果開發(fā)iPhone軟件,則不能使用垃圾回收。在編寫iPhone軟件時(shí),Apple公司建議不要在自己的代碼中使用autorelease方法,并且不要使用創(chuàng)建自動(dòng)釋放對(duì)象的函數(shù)。
類別
什么是類別?類別是一種為現(xiàn)有類添加新方法的方式。
為什么使用類別或者說使用類別的目的是什么?有以下三點(diǎn):
***,可以將類的實(shí)現(xiàn)分散到多個(gè)不同的文件或多個(gè)不同的框架中。
如果一個(gè)類需要實(shí)現(xiàn)很多個(gè)方法,我們可以將方法分類,把分好的類形成類別,可以有效的管理和駕馭代碼。
第二,創(chuàng)建對(duì)私有方法的前向引用。
第三,向?qū)ο筇砑臃钦絽f(xié)議。
委托
委托的意思就是你自己想做某事,你自己不做,你委托給別人做。
在Ojbective-C中,實(shí)現(xiàn)委托是通過類別(或非正式協(xié)議)或者協(xié)議來實(shí)現(xiàn)。
舉個(gè)例子:Apple要生產(chǎn)iPhone,Apple自己不生產(chǎn)(種種原因,其中之一就是在中國(guó)生產(chǎn)成本低,他們賺的銀子多),Apple委托富士 康來生 產(chǎn),本來富士康原來不生產(chǎn)iPhone,現(xiàn)在要生產(chǎn)了,所以他得自己加一個(gè)生產(chǎn)iPhone的生產(chǎn)線(類別,增加生產(chǎn)iPhone方法),這就是通過類別 來實(shí)現(xiàn)委托。下面用代碼來說明這個(gè)例子。
.....
Apple *apple = [[Apple alloc ] init];
Foxconn *fox = [[Foxconn alloc] init];
[apple setDelegate:fox];
[apple produceIPhone];
........
@implementation Apple
-(...) setDelegate:(id) x{
delegate = x; //! 將委托的生產(chǎn)對(duì)象指定為x
}
-(...) produceIPhone{
[delegate produceIPhone]; //! 委托對(duì)象生產(chǎn)iPhone
}
@interface Foxconn : NSObject
...
@end
@interface NSObject(ProduceIPhone) //! Foxconn之前就可以生產(chǎn)其它產(chǎn)品,有過聲明和定義
-(...) produceIPhone //! 增加生產(chǎn)iPhone能力
@end
@implementation NSObject(ProduceIPhone)
//! 生產(chǎn)iPhone
-(...) produceIPhone{
......
}
@end
別走開,下頁更精彩
#p#
非正式協(xié)議
創(chuàng)建一個(gè)NSObject的類別, 稱為創(chuàng)建一個(gè)非正式協(xié)議。為什么叫非正式協(xié)議呢?
也就是說可以實(shí)現(xiàn),也可以不實(shí)現(xiàn)被委托的任務(wù)。
拿上面的例子來說,Apple要求Foxconn除了能生產(chǎn)iPhone外,還有一個(gè)要求是在一定時(shí)間內(nèi)完成.由于雙方?jīng)]有簽合同,所以時(shí)間要求和生產(chǎn)要求規(guī)格都是非正式協(xié)議
選擇器
選擇器就是一個(gè)方法的名稱。選擇器是在Objective-C運(yùn)行時(shí)使用的編碼方式,以實(shí)現(xiàn)快速查找。可以使用@selector預(yù)編譯指令,獲取 選擇器 @selector(方法名)。NSObject提供了一個(gè)方法respondsToSelector:的方法,來訪問對(duì)象是否有該方法(響應(yīng)該消息)。
拿上面的Apple請(qǐng)F(tuán)oxconn生產(chǎn)iPhone為例,Apple怎么知道Foxconn有沒有生產(chǎn)iPhone的能力呢?Apple就通過 respondsToSelector方法詢問Foxconn,是否可以生產(chǎn)iPhone(是否可以響應(yīng)produceIPhone),詢問結(jié)果是可以, 那Apple就委托Foxconn生產(chǎn),F(xiàn)oxconn就生產(chǎn)出來了人們比較喜歡的iPhone產(chǎn)品。
正式協(xié)議
與非正式協(xié)議比較而言,在Ojbective-C中,正式協(xié)議規(guī)定的所有方法必須實(shí)現(xiàn)。在Ojbective-C2.0中,Apple又增加了兩個(gè)關(guān)鍵字,協(xié)議中的方法也可以不完全實(shí)現(xiàn),是哪個(gè)關(guān)鍵字見關(guān)鍵字部份的@optional,@required。
正式協(xié)議聲明如下:
@protocol XXX
-(...) func1;
-(...) func2;
@end
使用協(xié)議:
@interface Object : NSObject //! Object從NSObject派生,并遵循XXX協(xié)議,要實(shí)現(xiàn)func1,func2函數(shù)。
...
@end
習(xí)慣用法
分配內(nèi)存和初始化
self = [super init];
對(duì)象間交互
在Objective-C中,所有對(duì)象間的交互都是通過指針實(shí)現(xiàn)。
快速枚舉
for (Type *p in array)
注意:
Objective-C不支持多繼承
objective-c只不過是擁有一些附加特性的C語言。本質(zhì)上就是C語言
1.C語言使用#include通知編譯器應(yīng)在頭文件中查詢定義。objective-c也可以使用#include來實(shí)現(xiàn)這個(gè)目的,但你永遠(yuǎn)不可能這么做,你會(huì)用#import,它是GCC編譯器提供的,#import可以保證頭文件只被包含一次。
xcode會(huì)使用預(yù)編譯頭文件(一種經(jīng)過壓縮的,摘要形式的頭文件),在通過#import導(dǎo)入這種文件時(shí),加載速度會(huì)非???。
2.什么是框架
框架是一種聚集在一個(gè)單元的部件集合,包含頭文件,庫,圖像,聲音文件等。蘋果公司將cocoa,Carbon,QuickTime和OpenGL 等技術(shù) 作為框架集提供。cocoa的組成部分有Foundation和Application Kit框架。還有一個(gè)支持框架的套件,包含 Core Animation和Core Image,這為Cocoa增添了多種精彩的功能。
每個(gè)框架都是一個(gè)重要的技術(shù)集合,通常包含數(shù)十個(gè)甚至上百個(gè)頭文件。每個(gè)框架都有一個(gè)主頭文件,它包含了所有框架的各個(gè)頭文件。通過使用#import導(dǎo)入主頭文件,可以使用所有框架的特性。
3.Foundation框架處理的是用戶界面之下的層(layer)中得特性,例如數(shù)據(jù)結(jié)構(gòu)和通信機(jī)制。
4.NS前綴
NS這個(gè)前綴告訴你函數(shù)來自cocoa而不是其他工具包。
兩個(gè)不同事物使用相同標(biāo)示符時(shí)會(huì)導(dǎo)致名稱沖突,而前綴可以預(yù)防這個(gè)大問題。
5.BOOL類型
objective-c中得BOOL實(shí)際上是一種對(duì)帶符號(hào)的字符類型(signed char)的定義。它使用8位存儲(chǔ)空間,YES為1,NO為0.
6.間接
不在代碼中直接使用某個(gè)值,而是使用指向該值的指針。另一個(gè)意思是,讓別的類來完成本類的工作。
例子:
1.循環(huán)次數(shù)的變量。變量與間接
2.使用從文件讀取。文件與間接
在OOP(面向?qū)ο缶幊蹋┲?,間接十分重要。OOP使用間接來獲取數(shù)據(jù),OOP真正的革命性就是它在調(diào)用代碼中使用間接。比如在調(diào)用函數(shù)時(shí),不是直接調(diào)用,而是間接調(diào)用。
7.過程式程序與OOP的區(qū)別
過程式程序建立在函數(shù)之上,數(shù)據(jù)為函數(shù)服務(wù)。面向?qū)ο缶幊虖南喾吹慕嵌葋砜创龁栴}。它以程序的數(shù)據(jù)為中心,函數(shù)為數(shù)據(jù)服務(wù)。在OOP中,不在重點(diǎn)關(guān)注程序中得函數(shù),而是專注與數(shù)據(jù)。
8.id
id是一種泛型,用于表示任何種類的對(duì)象。
9.OOP中得一些術(shù)語
類:類是一種結(jié)構(gòu),它表示對(duì)象的類型。對(duì)象引用類來獲取和本身有關(guān)的各種信息,特別是運(yùn)行什么代碼來處理每種操作。
對(duì)象:對(duì)象是一種結(jié)構(gòu),它包含值和指向其類的隱藏指針。
實(shí)例:實(shí)例是“對(duì)象”的另一種稱呼。
消息:消息是對(duì)象可以執(zhí)行的操作,用于通知對(duì)象去做什么。
方法:方法是為響應(yīng)消息而運(yùn)行的代碼。根據(jù)對(duì)象的類,消息可以調(diào)用不同的方法。
方法調(diào)度程序:是objective-c使用的一種機(jī)制,用于推測(cè)執(zhí)行什么方法以響應(yīng)某個(gè)特定的消息。
接口:接口是對(duì)象的類應(yīng)該提供的特性的描述。接口不提供實(shí)現(xiàn)細(xì)節(jié)。
實(shí)現(xiàn):實(shí)現(xiàn)是使接口正常工作的代碼。
10.中綴符
objective-c有一種名為中綴符的語法技術(shù)。方法的名稱及其參數(shù)都是合在一起的。例如: [trxtThing setStringValue:@"Hello there" color:kBlueColor]; 中 setStringValue: 和 color:實(shí)際上是參數(shù)的名稱(實(shí)際上是方法名稱的一部分)。使代碼可讀性更強(qiáng),更容易理解參數(shù)的用途。
11.先行短線
-(void)draw;
前面的短線表明這是objective-c方法的生命。這是一種區(qū)分函數(shù)原型與方法聲明的方式,函數(shù)原型中沒有先行短線。-代表是實(shí)例方法。+代表是類方法。
12.@interface
創(chuàng)建某個(gè)特定類的對(duì)象之前,objective-c編譯器需要一些有關(guān)該類的信息。他必須知道對(duì)象的數(shù)據(jù)成員和它提供的特性可以使用@interface指令把這種信息傳遞給編譯器。用于定義類的公共接口。
13.@implementation
是一個(gè)編譯器指令,表明你將為某個(gè)類提供代碼。類名出現(xiàn)在@implementation之后。該行的結(jié)尾處沒有分號(hào)。因?yàn)樵趏bjective-c編譯器指令后不必使用分號(hào)。
@interface和@implementation間的參數(shù)名不同是正確的。
在@interface中沒有聲明卻在@implementation中實(shí)現(xiàn)的方法是私有方法。
14.實(shí)例化
創(chuàng)建對(duì)象的過程叫做實(shí)例化。實(shí)例化對(duì)象時(shí),需要分配內(nèi)存,然后這些內(nèi)存被初始化并保存一些有用的默認(rèn)值,這些值不同于你在獲得新分配內(nèi)存時(shí)得到的隨機(jī)值。內(nèi)存分配和初始化完成后,就創(chuàng)建了一個(gè)新的對(duì)象實(shí)例。
15.繼承
創(chuàng)建一個(gè)新類時(shí),通常需要定義新類以區(qū)別于其他類以及現(xiàn)有類。使用繼承可以定義一個(gè)具有父類所有功能的新類,它繼承了父類的這些功能。
objective-c沒有多繼承。
創(chuàng)建一個(gè)新類時(shí),其對(duì)象首先從自身的超類中繼承實(shí)例變量,然后添加他們自己的實(shí)例變量。
超類
父類
子類
孩子類
重寫
方法調(diào)度:objective-c的方法調(diào)度程序?qū)⒆赢?dāng)前類中搜索響應(yīng)的方法。如果調(diào)度程序無法在接受消息的對(duì)象類中找到響應(yīng)的方法,它就會(huì)在該類的超類中進(jìn)行查找。順著繼承鏈找到下一個(gè)超類進(jìn)行查找,直到NSObject類中也沒有該方法,則會(huì)出現(xiàn)運(yùn)行時(shí)錯(cuò)誤。
16.復(fù)合
對(duì)象引用其他對(duì)象時(shí),可以利用其他對(duì)象提供的特性,這就是復(fù)合。
17.UML
UML是一種用圖表表示類,類的內(nèi)容以及他們之間關(guān)系的常見方法。
18.多態(tài)
使用更具體種類的對(duì)象(子類對(duì)象)代替一般類型(父類),這種能力稱為多態(tài)性。
19.self
是一個(gè)指向接收消息的對(duì)象的指針。指向***個(gè)實(shí)例變量isa。因?yàn)閛bjective-c編譯器已經(jīng)看到了所有這些類的@interface聲明,因此,它能直到對(duì)象中實(shí)力變量的布局,通過這些重要的信息,編譯器可以產(chǎn)生代碼并查找任何需要的實(shí)例變量。
基地址加偏移:編譯器使用“基地址加偏移”機(jī)制實(shí)現(xiàn)奇妙的功能。給定的對(duì)象基地址,是指***個(gè)實(shí)例變量的***字節(jié)在內(nèi)存中得位置,通過在該地址加上偏移地址,編譯器就可以查到其他實(shí)例變量的位置。
20.間接尋址方式,直接尋址方式
21.super
objective-c提供某種方式來重寫方法,并且仍然調(diào)用超類的實(shí)現(xiàn)方式。當(dāng)需要超類實(shí)現(xiàn)自身的功能,同時(shí)在前面或者后面執(zhí)行某些額外的工作時(shí),這種機(jī)制非常有用。為了調(diào)用繼承方法的實(shí)現(xiàn),需要使用super作為方法調(diào)用的目標(biāo)。
22.cocoa
cocoa實(shí)際上是由2個(gè)不同的框架組成的:Foundation Kit和 Application Kit。Application Kit包含了所有的用戶接口對(duì)象和高級(jí)類。
Foundation Kit
23.NSAutoreleasePool
mian()函數(shù)創(chuàng)建了(通過alloc)并初始化(通過init)了一個(gè)NSAutoreleasePool實(shí)例。在mian()函數(shù)結(jié)尾,這個(gè)池被排空。這就是Cocoa內(nèi)存管理的預(yù)覽。
24.NSRange
typedef struct _NSRange {
unsigned int location;
unsigned int length;
}NSRange;
這個(gè)結(jié)構(gòu)體用來表示相關(guān)事務(wù)的范圍,通常是字符串里的字符范圍或者數(shù)組里的元素范圍。
25.三種賦值方式
1.NSRange range;
range.location = 17;
range.length = 4;
2.C語言的聚合結(jié)構(gòu)賦值機(jī)制
NSRange range = {17, 4};
3.Cocoa提供的一個(gè)快捷函數(shù)NSMakeRange()
NSRange range = NSMakeRange(17, 4);
使用NSMakeRange()的好處是你可以在任何能夠使用函數(shù)的地方使用它,例如在方法調(diào)用中將其當(dāng)成參數(shù)傳遞。
26.幾何數(shù)據(jù)類型
1.NSPoint 代表笛卡兒平面中得一個(gè)點(diǎn)(x, y).
typedef struct _NSPoint {
float x;
float y;
}NSPoint;
2.NSSize 用來存儲(chǔ)長(zhǎng)度和寬度
typedef struct NSSize {
float width;
float height;
}NSSize;
3.NSRect 矩形數(shù)據(jù)類型,它是由點(diǎn)和大小復(fù)合而成
typedef struct _NSRect {
NSPoint origin;
NSSize size;
}NSRect;
27.字符串NSString
stringWithFormat:就是一個(gè)工廠方法,它根據(jù)你提供的參數(shù)創(chuàng)建新對(duì)象。
length:長(zhǎng)度
isEqualToString:比較字符串內(nèi)容是否相同
compart:將接受對(duì)象和傳遞來的字符串逐個(gè)字符的進(jìn)行比較。返回一個(gè)enum數(shù)據(jù)
NSCaseInsensitiveSearch:不區(qū)分大小寫字符。
NSLiteralSearch:進(jìn)行完全比較,區(qū)分大小寫
NSNumericSearch:比較字符串的字符個(gè)數(shù),而不是字符值。
-(NSRange)rangeOfString:(NSString *)aString;
返回的range.start為開始位置,range.length為長(zhǎng)度。
28.NSMutableString可變字符串。
stringWithCapacity:創(chuàng)建一個(gè)新的NSMutableString
字符串的大小并不僅限于所提供的容量,這個(gè)容量?jī)H是個(gè)***值。如果要?jiǎng)?chuàng)建一個(gè)40mb的字符串。
NSMutableString *str = [NSMutableString stringWithCapacity:42];
appendString接受參數(shù)aString,然后將其復(fù)制到接收對(duì)象的末尾。
appendFormat與stringWithFormat:類似,但它將格式化的字符串附加在接收字符串的末尾,而不是創(chuàng)建新的字符串對(duì)象。
29.集合家族
1.NSArray:是一個(gè)Cocoa類,用來存儲(chǔ)對(duì)象的有序列表。
兩個(gè)限制:1.只能存儲(chǔ)objective-c的對(duì)象,不能存儲(chǔ)C語言中得基本數(shù)據(jù)類型。
2.也不能存儲(chǔ)nil。
30.枚舉器,快速枚舉
31.NSDictionary字典
關(guān)鍵字及其定義的集合。
32.NSNumber包裝(以對(duì)象形式實(shí)現(xiàn))基本數(shù)據(jù)類型
裝箱:將一個(gè)基本類型的數(shù)據(jù)包裝成對(duì)象。
取消裝箱:從對(duì)象中提取基本類型的數(shù)據(jù)。
objective-c不支持自動(dòng)裝箱。
33.NSValue是NSNumber的父類。
+(NSValue *)valueWithBytes:(const void *)value objCType:(const char *)type;
傳遞的參數(shù)是你想要包裝的數(shù)值的地址(如一個(gè)NSSize或你自己的struct)。通常,得到的是你想要存儲(chǔ)的變量的地址(在C語言中使用操作 符&)。你也可以提供一個(gè)用來描述這個(gè)數(shù)據(jù)類型的字符串,通常用來說明struct中實(shí)體的類型和大小。你不用自己寫代碼來生成這個(gè)字符 串,@encode編譯器指令可以接受數(shù)據(jù)類型的名稱并為你生成合適的字符串。
NSRect rect = NSMakeRect(1, 2, 30, 40);
NSValue *value;
value = [NSValue valueWithBytes:&rect objCType:@encode(NSRect)];
[array addObject:value];
34.NSNull只有一個(gè)方法[NSNull null];
[NSNull null]總是返回一樣的數(shù)值,所以你可以使用運(yùn)算符==將該值與其他值進(jìn)行比較。
35.單實(shí)例架構(gòu):只需要一個(gè)實(shí)例。
查找文件:
例如:NSFileManager *manager;
manager = [NSFileManager defaultManager];
defaultManager可以為我們創(chuàng)建一個(gè)屬于我們自己的NSFileManger對(duì)象。
NSString *home = [@"~" stringByExpandingTildeInPath];將~替換成當(dāng)前用戶的主目錄。
NSDirectoryEnumerator *direnum = [manager enumeratorAtPath:home];返回一個(gè) NSDictionaryEnumerator,它是NSEnumerator的子類。每次在這個(gè)枚舉器對(duì)象中調(diào)用nextObject時(shí),都會(huì)返回該目 錄中得一個(gè)文件的另一個(gè)路徑。
36.內(nèi)存管理
1)對(duì)象生命周期
對(duì)象的生命周期包括誕生(alloc或者new方法實(shí)現(xiàn)),生存(接受消息和執(zhí)行操作),交友(借助方法的組合和參數(shù))以及當(dāng)他們的生命結(jié)束時(shí)最終死去(被釋放)。當(dāng)對(duì)象的生命周期結(jié)束時(shí),他們的原材料(內(nèi)存)將被回收以供新的對(duì)象使用。
2)引用計(jì)數(shù)
cocoa采用了一種稱為引用計(jì)數(shù)的技術(shù),有時(shí)候也叫保留計(jì)數(shù)。每個(gè)對(duì)象有一個(gè)與之相關(guān)聯(lián)的整數(shù),稱作它的引用計(jì)數(shù)器或保留計(jì)數(shù)器。當(dāng)某段代碼需要 訪問一 個(gè)對(duì)象時(shí),該代碼將該對(duì)象的保留計(jì)數(shù)器值+1,表示“我要訪問該對(duì)象”。當(dāng)這段代碼結(jié)束對(duì)象訪問時(shí),將對(duì)象的保留計(jì)數(shù)器值-1,表示它不再訪問該對(duì)象,當(dāng) 保留計(jì)數(shù)器值為0時(shí),表示不再有代碼訪問該對(duì)象了,因此該對(duì)象被銷毀,其占用的內(nèi)存被系統(tǒng)回收以便重用。
alloc,new,copy 1
retain +1
release -1
3)對(duì)象所有權(quán)
如果一個(gè)對(duì)象具有指向其他對(duì)象的實(shí)力變量,則稱該對(duì)象擁有這些對(duì)象。
在類A中 B對(duì)象擁有其指向的C對(duì)象,則B對(duì)象擁有C對(duì)象。
如果一個(gè)函數(shù)創(chuàng)建了一個(gè)對(duì)象,則稱該函數(shù)擁有它創(chuàng)建的這個(gè)對(duì)象。
main()函數(shù)創(chuàng)建了對(duì)象a 稱main()函數(shù)擁有a對(duì)象
當(dāng)多個(gè)實(shí)體擁有某個(gè)特定的對(duì)象時(shí),對(duì)象的所有權(quán)關(guān)系就更加復(fù)雜了,這也是保留計(jì)數(shù)器值可能大于1的原因。
例子:
main() {
Engine *engine = [Engine new];
[car setEngine:engine];
}
現(xiàn)在哪個(gè)實(shí)體擁有engine對(duì)象?是main函數(shù)還是car類?哪個(gè)實(shí)體負(fù)責(zé)確保當(dāng)engine對(duì)象不再被使用時(shí)能夠收到release消息?因 為 car類正在使用engine對(duì)象,所以不可能是main函數(shù)。因?yàn)閙ain函數(shù)隨后還可能會(huì)使用engine對(duì)象,所以也不可能是car類。
解決方法是讓car類保留engine對(duì)象,將engine對(duì)象的保留計(jì)數(shù)器值增加到2。這是因?yàn)閏ar類和main函數(shù)這2個(gè)實(shí)體都正在使用 engine對(duì)象。car類應(yīng)該在setEngine:方法中保留engine對(duì)象,而main函數(shù)應(yīng)該釋放engine對(duì)象。然后,當(dāng)car類完成其任 務(wù)時(shí)再釋放engine對(duì)象(在其dealloc方法中),***engine對(duì)象占用的資源被回收。
如果您使用名字以“alloc”或“new”開頭或名字中包含“copy”的方法(例如alloc,newObject或mutableCopy) 創(chuàng)建了 一個(gè)對(duì)象,則您會(huì)獲得該對(duì)象的所有權(quán);或者如果您向一個(gè)對(duì)象發(fā)送了一條retain消息,則您也會(huì)獲得該對(duì)象的所有權(quán)。
4)訪問方法中得保留和釋放
5)自動(dòng)釋放池NSAutoreleasePool
是一個(gè)存放實(shí)體的池(集合)。你可以用NSMutableArray來編寫自己的自動(dòng)釋放池,以容納對(duì)象并在dealloc方法中向池中得所有對(duì)象發(fā)送release消息。
autorelease
當(dāng)給一個(gè)對(duì)象發(fā)送autorelease消息時(shí),實(shí)際上是將該對(duì)象添加到NSAutoreleasePool中。當(dāng)自動(dòng)釋放池被銷毀時(shí),會(huì)向該池中得所有對(duì)象發(fā)送release消息。
6)自動(dòng)釋放池的銷毀時(shí)間
在我們一直使用的Foudation庫工具中,創(chuàng)建和銷毀自動(dòng)釋放池的方法非常明確:
NSAutoreleasePool *pool;
pool = [[NSAutoreleasePool alloc] init];
...
[pool release];
創(chuàng)建一個(gè)自動(dòng)釋放池時(shí),該池自動(dòng)成為活動(dòng)的池。釋放該池時(shí),其保留計(jì)數(shù)器值歸0,然后該池被銷毀。在銷毀的過程中,該池釋放其包含的所有對(duì)象。當(dāng)使 用 Application Kit時(shí),cocoa定期自動(dòng)為你創(chuàng)建和銷毀自動(dòng)釋放池。通常是在程序處理完當(dāng)前事件以后執(zhí)行這些操作。你可以使用任意多得自動(dòng) 釋放對(duì)象,當(dāng)不再使用它們時(shí),自動(dòng)釋放池將自動(dòng)為你清理這些對(duì)象。
你可能已經(jīng)在xcode自動(dòng)生成代碼中遇見過另一種銷毀自動(dòng)釋放池中對(duì)象的方式:-drain方法。該方法只是清空自動(dòng)釋放池而不是銷毀它。并且只適用于mac os x10.4以上的版本。
7)自動(dòng)釋放池的工作過程
我們?cè)谌魏螘r(shí)候向一個(gè)對(duì)象發(fā)送autorelease消息,該對(duì)象都會(huì)唄添加到這個(gè)自動(dòng)釋放池中。被加入到自動(dòng)釋放池的對(duì)象的引用計(jì)數(shù)器值不會(huì)變 化。當(dāng)自 動(dòng)釋放池被銷毀時(shí)(向自動(dòng)釋放池發(fā)送release消息,自動(dòng)釋放池的引用計(jì)數(shù)器值變?yōu)?,調(diào)用自身的dealloc函數(shù)),會(huì)調(diào)用自身的dealloc 函數(shù),會(huì)向池中得對(duì)象發(fā)送release消息。
別走開,下頁更精彩
#p#
37.cocoa內(nèi)存管理規(guī)則
1)當(dāng)你使用new,alloc或copy方法創(chuàng)建一個(gè)對(duì)象時(shí),該對(duì)象的保留計(jì)數(shù)器值為1。當(dāng)不再使用該對(duì)象時(shí),你要負(fù)責(zé)向該對(duì)象發(fā)送一條release或autorelease消息。這樣,該對(duì)象將在其使用壽命結(jié)束時(shí)被銷毀。
2)當(dāng)你通過任何其他方法獲得一個(gè)對(duì)象時(shí),則假設(shè)該對(duì)象的保留計(jì)數(shù)器值為1,而且已經(jīng)被設(shè)置為自動(dòng)釋放,你不需要執(zhí)行任何操作來確保該對(duì)象被清理。如果你打算在一段時(shí)間內(nèi)擁有該對(duì)象,則需要保留它并確保在操作完成時(shí)釋放它。
3)如果你保留了某個(gè)對(duì)象,你需要(最終)釋放或自動(dòng)釋放該對(duì)象。必須保持retain方法和release方法的使用次數(shù)相同。
38.清理自動(dòng)釋放池
由于自動(dòng)釋放池的銷毀時(shí)間是完全確立的,所以它在循環(huán)執(zhí)行過程中不會(huì)被銷毀。在迭代中或者循環(huán)中,需要建立自己的自動(dòng)釋放池。
39.垃圾回收gc
自動(dòng)內(nèi)存管理機(jī)制。objective-c的垃圾回收器是一種繼承性的垃圾回收器。與那些已經(jīng)存在了一段時(shí)間的對(duì)象相比,新創(chuàng)建的對(duì)象更可能被當(dāng)成 垃圾。 垃圾回收器定期檢查變量和對(duì)象以及他們之間的指針,當(dāng)發(fā)現(xiàn)沒有任何變量指向某個(gè)對(duì)象時(shí),就將該對(duì)象視為應(yīng)該被丟棄的垃圾。如果你再一個(gè)實(shí)例變量中指向某個(gè) 對(duì)象,一定要在某個(gè)時(shí)候使該實(shí)例變量賦值為nil,以取消對(duì)該對(duì)象的引用并使垃圾回收器知道該對(duì)象可以被清理了。
與自動(dòng)釋放池一樣,垃圾回收器也是在時(shí)間循環(huán)結(jié)束時(shí)才觸發(fā)。
ARC是什么?
ARC是iOS 5推出的新功能,全稱叫 ARC(Automatic Reference Counting)。簡(jiǎn)單地說,就是代碼中自動(dòng)加入了retain/release,原先需要手動(dòng)添加的用來處理內(nèi)存管理的引用計(jì)數(shù)的代碼可以自動(dòng)地由編譯器完成了。
該機(jī)能在 iOS 5/ Mac OS X 10.7 開始導(dǎo)入,利用 Xcode4.2 可以使用該機(jī)能。簡(jiǎn)單地理解ARC,就是通過指定的語 法,讓編 譯器(LLVM 3.0)在編譯代碼時(shí),自動(dòng)生成實(shí)例的引用計(jì)數(shù)管理部分代碼。有一點(diǎn),ARC并不是GC,它只是一種代碼靜態(tài)分析 (Static Analyzer)工具。
40.分配
是一個(gè)新對(duì)象誕生的過程。是從操作系統(tǒng)獲得一塊內(nèi)存并將其指定為存放對(duì)象的實(shí)例變量的位置。
40.初始化
與分配對(duì)應(yīng)的操作是初始化。初始化從操作系統(tǒng)取得一塊內(nèi)存。準(zhǔn)備用于存儲(chǔ)對(duì)象。
嵌套調(diào)用技術(shù)非常重要,因?yàn)槌跏蓟椒ǚ祷氐膶?duì)象可能與分配的對(duì)象不同。
1)初始化時(shí)做什么?
給實(shí)例變量賦值并創(chuàng)建你得對(duì)象完成任務(wù)所需要的其他對(duì)象。
2)便利初始化函數(shù)
許多類包含便利初始化函數(shù)。用來完成某些額外的工作的初始化方法,可以減少你自己完成這些工作的麻煩。
例如:NSString類中-(id)initWithFormat:(NSString *)format,...;
3)指定初始化函數(shù)
類中的某個(gè)初始化方法被指派為指定初始化函數(shù)。該類所有初始化方法使用指定初始化函數(shù)執(zhí)行初始化操作。子類使用其超類的指定初始化函數(shù)實(shí)現(xiàn)超類的初始化。
例如:其他初始化函數(shù)通過指定初始化函數(shù)實(shí)現(xiàn)。
41.初始化函數(shù)規(guī)則
不需要為你自己的類創(chuàng)建初始化函數(shù)方法。如果不需要設(shè)置任何狀態(tài),或者只需要alloc方法將內(nèi)存清零的默認(rèn)行為,則不需要擔(dān)心init。
如果構(gòu)造了一個(gè)初始化函數(shù),則一定要在你自己的指定初始化函數(shù)中調(diào)用超類的指定初始化函數(shù)。一定要將超類的初始化函數(shù)的值賦給self對(duì)象,并返回你自己的初始化方法的值。因?yàn)槌惪赡軟Q定返回一個(gè)完全不同的對(duì)象。
如果初始化函數(shù)不止一個(gè),則要選擇一個(gè)座位指定初始化函數(shù)。被選定的方法應(yīng)該調(diào)用超類指定初始化函數(shù)。要按照指定初始化函數(shù)的形式實(shí)現(xiàn)所有其他初始化函數(shù),就像我們?cè)谇懊娴膶?shí)現(xiàn)一樣。
42.特性@property
objective-c2.0的特性只適用于mac os x 10.5或更高版本。特性主要應(yīng)用于cocoa的新組件(尤其是華麗奪目的core Animation效果)。
1)簡(jiǎn)化接口
@property預(yù)編譯指令的作用是自動(dòng)生命屬性的setter和getter方法。
2)@synthesize也是一種新的編譯器功能,表示“創(chuàng)建該屬性的訪問器”。
3)點(diǎn)表達(dá)式
如果點(diǎn)表達(dá)式出現(xiàn)在=左邊,該屬性名稱的setter方法(set方法)將被調(diào)用。如果點(diǎn)表達(dá)式出現(xiàn)在對(duì)象變量右邊,則該屬性名稱的getter方法(get方法)將被調(diào)用。
4)特性擴(kuò)展
@property()括號(hào)里面的東西,是對(duì)應(yīng)在set方法中要添加的語句。比如我在括號(hào)里寫retain,就相當(dāng)于在它的set方法里添加了一句 [xx retain]。
@property屬性
屬性分為3類:
1.讀寫屬性(Writability)包含:readwrite / readonly
2.setter語義(Setter Semantics)包含:assign / retain / copy
3.原子性(Atomicity)包含:nonatomic
下面具體說明各個(gè)屬性的含義
readwrite / readonly:
決定是否生成set訪問器,readwrite是默認(rèn)屬性,生成getter和setter方法;readonly只生成getter方法,不生成setter方法。
readonly關(guān)鍵字代表setter不會(huì)被生成, 所以它不可以和 copy/retain/assign組合使用。
assign / retain / copy:
這些屬性用于指定set訪問器的語義,也就是說,這些屬性決定了以何種方式對(duì)數(shù)據(jù)成員賦予新值。
assign:
直接賦值,索引計(jì)數(shù)不改變,適用于簡(jiǎn)單數(shù)據(jù)類型,例如:NSIngeter、CGFloat、int、char等。
retain:
指針的拷貝,使用的是原來的內(nèi)存空間。
對(duì)象的索引計(jì)數(shù)加1。
此屬性只能用于Objective-C對(duì)象類型,而不能用于Core Foundation對(duì)象。(原因很明顯,retain會(huì)增加對(duì)象的引用計(jì)數(shù),而基本數(shù)據(jù)類型或者Core Foundation對(duì)象都沒有引用計(jì)數(shù))。
copy:
對(duì)象的拷貝,新申請(qǐng)一塊內(nèi)存空間,并把原始內(nèi)容復(fù)制到那片空間。
新對(duì)象的索引計(jì)數(shù)為1。
此屬性只對(duì)那些實(shí)行了NSCopying協(xié)議的對(duì)象類型有效。
很多Objective-C中的object***使用用retain,一些特別的object(例如:string)使用copy。
nonatomic:
非原子性訪問,不加同步,多線程并發(fā)訪問會(huì)提高性能。如果不加此屬性,則默認(rèn)是兩個(gè)訪問方法都為原子型事務(wù)訪問。默認(rèn)值是atomic,為原子操作。
(atomic是Objc使用的一種線程保護(hù)技術(shù),基本上來講,是防止在寫未完成的時(shí)候被另外一個(gè)線程讀取,造成數(shù)據(jù)錯(cuò)誤。而這種機(jī)制是耗費(fèi)系統(tǒng)資源的, 所以在iPhone這種小型設(shè)備上,如果沒有使用多線程間的通訊編程,那么nonatomic是一個(gè)非常好的選擇。)
5)保留周期retain cycle
引用計(jì)數(shù)器在該周期中歸零。
6)什么是屬性訪問器
屬性訪問器(Property Accessor),包括 get 訪問器和 set 訪問器分別用于字段的讀寫操作
其設(shè)計(jì)目的主要是為了實(shí)現(xiàn)面向?qū)ο螅∣O)中的封裝思想。根據(jù)該思想,字段***設(shè)為private,一個(gè)精巧的類***不要直接把字段設(shè)為公有提供給客戶調(diào)用端直接訪問
另外要注意屬性本身并不一定和字段相聯(lián)系
7)self.a與a的區(qū)別
self.a使編譯器知道我們期望使用訪問器訪問a。如果只使用裸名a,編譯器將假設(shè)我們直接修改了實(shí)例變量。
8)self.a = nil
這行代碼表示使用nil參數(shù)調(diào)用setName:方法。生成的訪問器方法將自動(dòng)釋放以前的name對(duì)象,并使用nil替代a。該方法完成了釋放 name對(duì) 象所占用內(nèi)存的操作。當(dāng)然,也可以只釋放name對(duì)象以清理其占用的內(nèi)存。如果你再dealloc方法以外的地方清除特性,那么使用"將nil賦值給對(duì) 象"的方法可以將特性設(shè)置為nil,同時(shí)可以使我們避免對(duì)已釋放內(nèi)存的懸空引用問題。
9)特性不是***的
有些方法不適合特性所能涵蓋的方法的相當(dāng)狹小的范圍。特性不支持那些需要接受額外參數(shù)的方法。
43.類別@category
1)聲明類別
@interface NSString (NumberConvenience)
-(NSNumber *)lengthAsNumber;
@end
該聲明具有2個(gè)特點(diǎn)。首先,現(xiàn)有類位于@interface關(guān)鍵字之后,其后是位于圓括號(hào)中的一個(gè)新名稱。該聲明表示,類別的名稱是 NumberConvenience,而且該類別將向NSString類中添加方法。只要保證類別名稱的唯一性,你可以向一個(gè)類中添加任意多得類別。
其次,你可以指定希望向其添加類別的類以及類別的名稱,而且你還可以列出添加的方法,***以@end結(jié)束。由于不能添加新實(shí)現(xiàn)變量,因此與類聲明不同的是,類別的聲明中沒有實(shí)例變量部分。
2)實(shí)現(xiàn)類別
3)類別的局限性
***,無法向類中添加新的實(shí)例變量。類別沒有位置容納實(shí)例變量。
第二,名稱沖突,即類別中得方法與現(xiàn)有的方法重名。當(dāng)發(fā)生名稱沖突時(shí),類別具有更高的優(yōu)先級(jí)。你得類別方法將完全取代初始方法,從而無法再使用初始方法。有些編程人員在自己的類別方法中增加一個(gè)前綴,以確保不發(fā)生名稱沖突。
有一些技術(shù)可以克服類別無法增加新實(shí)例變量的局限。例如,可以使用全局字典存儲(chǔ)對(duì)象與你想要關(guān)聯(lián)的額外變量之間的映射。但此時(shí)你可能需要認(rèn)真考慮一下,類別是否是完成當(dāng)前任務(wù)的***選擇。
4)類別的作用
cocoa中得類別主要用于3個(gè)目的:***,將類的實(shí)現(xiàn)分散到不同文件或者不同框架中。第二,創(chuàng)建對(duì)私有方法的前向引用。第三,向?qū)ο筇砑臃钦絽f(xié)議。
44.run循環(huán)是一種cocoa構(gòu)造,它一直處于阻塞狀態(tài)(即不執(zhí)行任何處理),知道某些事件發(fā)生為止。
45.響應(yīng)選擇器
一個(gè)類別如何知道其委托對(duì)象是否能夠處理那些發(fā)送給它的消息?
類別首先檢查對(duì)象,詢問其能否響應(yīng)該選擇器。如果該對(duì)象能夠響應(yīng)該選擇器,
1)選擇器@selector()
選擇器只是一個(gè)方法名稱,但它以objective-c運(yùn)行時(shí)使用的特殊方式編碼,以快速執(zhí)行查詢。你可以使用@selector()預(yù)編譯指令選擇器,其中方法名位于圓括號(hào)中。
46.委托 非正式協(xié)議
47.正式協(xié)議
與非正式協(xié)議一樣,正式協(xié)議是一個(gè)命名的方法列表。但與非正式協(xié)議不同的是,正式協(xié)議要求顯式的采用協(xié)議。采用協(xié)議的辦法是在類的@interface聲明中列出協(xié)議名稱。采用協(xié)議意味著你承諾實(shí)現(xiàn)該協(xié)議的所有方法。
1)聲明協(xié)議
@protocol NSCopying
-(id)copyWithZone:(NSZone *)zone;
@end
2)采用協(xié)議
@interface Car: NSObject <NSCopying>
{
}
@end
3)協(xié)議和數(shù)據(jù)類型
如果一個(gè)用尖括號(hào)括起來的協(xié)議名稱跟隨在id之后,則編譯器將知道你期望任意類型的對(duì)象,只要其遵守該協(xié)議。
4)objective-c2.0的新特性@optional @required
@optional可選擇實(shí)現(xiàn)的方法
@required必須實(shí)現(xiàn)的方法
因此cocoa中得非正式協(xié)議正被帶有@optional的正式協(xié)議所取代。
48.Application Kit
1)IBOutlet與IBAction
他們實(shí)際上只是APPKit提供的#defines。IBOutlet的定義沒有任何作用,因此將不會(huì)對(duì)它進(jìn)行編譯。IBAction定義為 void,這 意味著在AppController中聲明的方法的返回類型將使void。IBOutlet和IBAction不執(zhí)行任何操作,他們并不是用于編譯的,實(shí) 際上他們是為Interface Builder以及閱讀代碼的人提供的標(biāo)記。通過查找IBOutlet和 IBAction,Interface Builder知道AppController對(duì)象具有兩個(gè)能夠連接的實(shí)例變量。
2)IBOutlet是如何工作的
當(dāng)加載nib文件時(shí)(MainMenu.nib會(huì)在應(yīng)用程序啟動(dòng)時(shí)自動(dòng)加載,可以創(chuàng)建你自己的nib文件并自行加載),存儲(chǔ)在nib文件中得任何對(duì) 象都會(huì) 被重新創(chuàng)建。這意味著會(huì)再后臺(tái)執(zhí)行alloc和init方法。所以,當(dāng)應(yīng)用程序啟動(dòng)時(shí),會(huì)分配并初始化一個(gè)AppController實(shí)例。在執(zhí)行 init方法期間,所有IBOutlet實(shí)例變量都為nil。只有創(chuàng)建了nib文件中得所有對(duì)象(這包括窗口和文本域和按鈕),所有連接才算完成。
一旦建立了所有連接(也就是將NSTextField對(duì)象的地址添加到AppController的實(shí)例變量中),會(huì)向創(chuàng)建的每個(gè)對(duì)象發(fā)送消息 awakeFromNib。一個(gè)非常常見的錯(cuò)誤是試圖在init方法中使用IBOutlet執(zhí)行一些操作。由于所有實(shí)例變量都為nil,發(fā)送給他們的所有 消息不執(zhí)行任何操作,所以在init中得任何嘗試都會(huì)發(fā)生無提示失敗。(這是Cocoa導(dǎo)致效率低和占用大量調(diào)試時(shí)間的一個(gè)方面)。如果你想知道為什么這 些操作不起作用,可以使用NSLog輸出實(shí)例變量的值,并查看他們是否都為nil。對(duì)于創(chuàng)建的對(duì)象和發(fā)送的awakeFromNib消息,都不存在預(yù)定義 順序。
文件加載與保存
49.屬性列表
1)自動(dòng)釋放對(duì)象
NSDate
NSData NSData對(duì)象是不可改變的。他們被創(chuàng)建后就不能改變??梢允褂盟麄儯荒芨淖兤渲械膬?nèi)容。
2)編碼對(duì)象 編碼和解碼
cocoa具備一種機(jī)制來將對(duì)象自身轉(zhuǎn)換為某種格式并保存到磁盤中。對(duì)象可以將他們的實(shí)例變量和其他數(shù)據(jù)塊編碼為數(shù)據(jù)塊,然后保存到磁盤中。以后將這些數(shù)據(jù)塊讀回到內(nèi)存中,并且還能基于保存的數(shù)據(jù)創(chuàng)建新對(duì)象。這個(gè)過程稱為編碼和解碼?;蚍Q為序列化和反序列化。
50.鍵/值編碼 KVC
是一種間接改變對(duì)象狀態(tài)的方式,其實(shí)現(xiàn)方法是使用字符串描述要更改的對(duì)象狀態(tài)部分。
1)valueForKey與setValue:forKey:
這兩種方法的工作方式相同。他們首先查找名稱的setter(getter)方法,如果不存在setter(getter)方法,他們將在類中查找名為名稱或_名稱的實(shí)例變量。然后給它賦值(取值)。無需通過對(duì)象指針直接訪問實(shí)例變量。
2)路徑
鍵路徑的深度是任意的,具體取決于對(duì)象圖。
鍵路徑不僅能引用對(duì)象值,還可以引用一些運(yùn)算符來進(jìn)行一些運(yùn)算,例如獲取一組值的平均值或返回這組值中得最小值和***值。
例如:NSNumber *count;
count = [garage valueForKeyPath:@"cars.@count"];
NSLog(@"We have %@ cars", count);
我們將路徑“cars.@count”拆開,cars用于獲取cars屬性,它是來自garage的NSArray類型的值。接下來的部分是@count ,其中@符號(hào)意味著后面將進(jìn)行一些運(yùn)算。
和 cars@sun.mileage
***值 cars@min.mileage
最小值 cars@max.mileage
3)整體操作
KVC非常棒的一點(diǎn)是,如果向NSArray請(qǐng)求一個(gè)鍵值,它實(shí)際上會(huì)查詢數(shù)組中得每個(gè)對(duì)象來查找這個(gè)鍵值,然后將查詢結(jié)果打包到另一個(gè)數(shù)組中并返回給你。這種方法也適用于通過鍵路徑訪問的對(duì)象內(nèi)部的數(shù)組。
4)批處理
KVC包含兩個(gè)調(diào)用,可以使用他們對(duì)對(duì)象進(jìn)行批量更改。***個(gè)調(diào)用是dictionaryWith-ValuesForKeys:。它接受一個(gè)字符串?dāng)?shù)組。該調(diào)用獲取一些鍵,對(duì)每個(gè)鍵使用valueForKey:,然后為鍵字符串和剛才獲取的值構(gòu)建一個(gè)字典。