Cocoa學(xué)習(xí)筆記 設(shè)計(jì)模式詳解
Cocoa學(xué)習(xí)筆記 設(shè)計(jì)模式詳解是本文要介紹的內(nèi)容,文章中中讓我們從多個(gè)方面去了解和學(xué)習(xí)Cocoa的設(shè)計(jì)模式,不多說(shuō),我們來(lái)看內(nèi)容。
枚舉器
類似于java容器類中的iterator,用以遍歷類中的元素
- NSDictionary *Mycollection;
 - NSEnumerator *enumerator=[Mycollection objectEnumerator];
 - while (instance=[enumerator nextObject]) {
 - //
 - }
 
***的objective c引入了快速枚舉,如下所示:
- id instance;
 - NSDictionary *Mycollection;
 - NSEnumerator *enumerator=[Mycollection objectEnumerator];
 - for (instance in Mycollection) {
 - //
 - }
 
NSEnumerator類本身也支持快速枚舉,因此可以采用下面的方式反序枚舉容器中的數(shù)據(jù)
- id instance;
 - NSArray *Mycollection;
 - NSEnumerator *enumerator=[Mycollection objectEnumerator];
 - for (instance in [Mycollection reverseObjectEnumerator]) {
 - //
 - }
 
要?jiǎng)?chuàng)建自定義的枚舉器,那么就要繼承NSEnumerator類,重要是override nextObject方法
要實(shí)現(xiàn)快速枚舉就必須實(shí)現(xiàn)NSFastEnumeration協(xié)議,主要是實(shí)現(xiàn)以下方法
- - (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state objects:(id *)stackbuf count:(NSUInteger)len;
 
執(zhí)行選擇器和延遲執(zhí)行
在cocoa中對(duì)象的方法調(diào)用是采用一種消息的方式來(lái)執(zhí)行的,因此就需要對(duì)象能夠執(zhí)行某個(gè)操作,發(fā)送什么消息才能讓對(duì)象啟動(dòng)執(zhí)行某個(gè)操作,發(fā)送的消息的內(nèi)容
在cocoa中采用選擇器的方式確定發(fā)送給對(duì)象的消息,并且接收消息的對(duì)象使用選擇器來(lái)選擇調(diào)用哪個(gè)方法
- //聲明一個(gè)selector并初始化
 - SEL aSelector=@selector(application:didChangeStatusBarFrame:);
 - //聲明一個(gè)selector不初始化
 - SEL bSelector;
 - //向?qū)ο蟀l(fā)送selector
 - id result1=[Mycollection performSelector:aSelector];
 - id result2=[Mycollection performSelector:@selector(application:didChangeStatusBarFrame:)];
 - //檢測(cè)對(duì)象是否支持該方法
 - if ([Mycollection respondsToSelector:aSelector]) {
 - //OK
 - }
 - //動(dòng)態(tài)創(chuàng)建類和selector
 - id class=[[NSClassFromString(@"TestTableAppDelegate") alloc] init];
 - [class performSelector:NSSelectorFromString([NSString stringWithFormat:@"setA%i",i])];
 
selector的基本原理就是apple的運(yùn)行庫(kù)通過(guò)在類自身內(nèi)緩沖每個(gè)選擇器的IMP來(lái)快速搜索對(duì)應(yīng)的函數(shù)指針,也可以自己找到對(duì)應(yīng)的指針
- [Mycollection methodForSelector:aSelector];
 - [NSDictionary instanceMethodForSelector:aSelector];
 
歸檔與解檔
說(shuō)白了就是對(duì)象序列化
- NSData *data=[NSKeyedArchiver archivedDataWithRootObject:self.window];
 - //用戶默認(rèn)數(shù)據(jù)存取
 - //存到默認(rèn)數(shù)據(jù)中
 - [[NSUserDefaults standardUserDefaults] setObject:data forKey:@"窗口數(shù)據(jù)"];
 
通過(guò)類似的技術(shù)可以把符合協(xié)議的任何對(duì)象進(jìn)行歸檔,下面是協(xié)議的定義,***個(gè)用于歸檔的時(shí)候,第二個(gè)用于解檔的時(shí)候
- @protocol NSCoding
 - - (void)encodeWithCoder:(NSCoder *)aCoder;
 - - (id)initWithCoder:(NSCoder *)aDecoder;
 - @end
 
對(duì)象要支持歸檔與解檔就必須實(shí)現(xiàn)NSCoding協(xié)議
如果對(duì)象是繼承于父類,那么在實(shí)現(xiàn)NSCoding協(xié)議的時(shí)候還必須調(diào)用父類的對(duì)應(yīng)方法,如下所示
- @implementation TestClass
 - @synthesize test1=_test1;
 - static NSString *CodingKeyTest1=@"Test1";
 - - (void)encodeWithCoder:(NSCoder *)aCoder{
 - [aCoder encodeObject:self.test1 forKey:CodingKeyTest1];
 - }
 - - (id)initWithCoder:(NSCoder *)aDecoder{
 - if (nil!=(self=[super initWithCoder:aDecoder])) {
 - [self setTest1:[aDecoder decodeObjectForKey:CodingKeyTest1]];
 - }
 - return self;
 - }
 - @end
 
cocoa單態(tài)模式舉例
書(shū)上的例子很多是錯(cuò)誤的,不知道怎么搞的
- static TestClass *_shareInstance=nil;
 - - (void)encodeWithCoder:(NSCoder *)aCoder{
 - _test2=@"test";
 - self->_test2=@"test2";
 - [aCoder encodeObject:self.test1 forKey:CodingKeyTest1];
 - }
 - - (id)initWithCoder:(NSCoder *)aDecoder{
 - if (nil!=(self=[super initWithCoder:aDecoder])) {
 - [self setTest1:[aDecoder decodeObjectForKey:CodingKeyTest1]];
 - }
 - return self;
 - }
 - (id)hiddenAlloc{
 - return [super alloc];
 - }
 - //單態(tài)模式,不允許創(chuàng)建對(duì)象
 - (id)alloc{
 - return [[self shareInstance] retain];
 - }
 - (id)new{
 - return [self alloc];
 - }
 - (id)allocWithZone:(NSZone *)zone{
 - return [[self shareInstance] retain];
 - }
 - - (id)copyWithZone:(NSZone *)zone{
 - return [[self shareInstance] retain];
 - }
 - - (id)mutableCopyWithZone:(NSZone *)zone{
 - [self copyWithZone:zone];
 - return self;
 - }
 - + (TestClass*)shareInstance{
 - if (_shareInstance==nil) {
 - _shareInstance=[[super allocWithZone:NULL] init];
 - }
 - return _shareInstance;
 - }
 
通知
書(shū)上的例子很多是錯(cuò)誤的,不知道怎么搞的
所謂通知也就是消息監(jiān)聽(tīng)響應(yīng)模式,和MFC的實(shí)現(xiàn)有些類似,下面給個(gè)例子
要想對(duì)象能夠接收消息,那么就必須先把對(duì)象注冊(cè)到對(duì)象通知中心
- typedef struct {
 - int id;
 - float height;
 - unsigned char flag;
 - }MyTestStruct;
 - //將對(duì)象注冊(cè)到消息接收泵中
 - [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(textViewDidChangeSelection:) name:
 - @"NSTextViewDidChangeSelection" object:nil];
 - //對(duì)象接收到消息做出對(duì)應(yīng)處理的代碼
 - + (void)textViewDidChangeSelection:(NSNotification *)aNotification{
 - NSValue *oldValue=[[aNotification userInfo] objectForKey:@"用鍵值查找數(shù)據(jù)"];
 - MyTestStruct _teststruct;
 - [oldValue getValue:&_teststruct];
 - NSLog(@"%f打印結(jié)果咯",_teststruct.height);
 - }
 - //發(fā)送消息給對(duì)象
 - - (void) postMessage{
 - //發(fā)送通知
 - MyTestStruct _teststruct;
 - _teststruct.id=0;
 - _teststruct.height=10.2;
 - NSValue *_value=[NSValue valueWithBytes:&_teststruct objCType:@encode(MyTestStruct)];
 - NSDictionary *_dic=[[NSDictionary alloc] initWithObjectsAndKeys:_value, @"用鍵值查找數(shù)據(jù)",nil];
 - [[NSNotificationCenter defaultCenter] postNotificationName:@"NSTextViewDidChangeSelection" object:self userInfo:_dic];
 - }
 
委托
說(shuō)白了,就是另外一個(gè)對(duì)象的引用
比如A要給B發(fā)送消息,那么A中就保存一個(gè)B的實(shí)例引用,所以在cocoa的類中很多內(nèi)部都有個(gè)無(wú)類型的實(shí)例變量
- id delegate;
 
再比如資源文件創(chuàng)建的窗口也有一個(gè)delegate,這個(gè)delegate要連接到某個(gè)類的delegate,那么這個(gè)類的委托就可以這樣聲明
- @property(nonatomic,readwrite,assign) IBOutlet id delegate;
 
也可以定義成符合某種protocol的委托,如下:
- @property(nonatomic,readwrite,assign) IBOutlet id<UITableViewDelegate> delegate;
 
插座 目標(biāo) 動(dòng)作
插座變量主要用于連接Nib文件創(chuàng)建的實(shí)例,在從nib文件中加載并初始化了所有對(duì)象之后,將給加載的每個(gè)對(duì)象發(fā)送一條如下所示的消息
- - (void)awakeFromNib;
 
對(duì)象接收到這個(gè)消息后就會(huì)把它的所有插座變量都設(shè)置為在Interface Builder中給它們提供的值
所謂目標(biāo)就是target,在cocoa中很多類都提供了一個(gè)名為target的插座變量和對(duì)應(yīng)名為action的實(shí)例變量
NSControl NSActionCell NSMenuItem實(shí)現(xiàn)了setTarget方法來(lái)設(shè)置目標(biāo)
任何返回void并且接受一個(gè)對(duì)象參數(shù)的方法都可以用作動(dòng)作
用setAction方法來(lái)設(shè)置動(dòng)作
不管發(fā)送動(dòng)作消息是為了干什么,都是使用NSApplication類的-sendAction:to:from:方法來(lái)完成發(fā)送
NSApplication類是一個(gè)單態(tài)類,因此發(fā)送動(dòng)作時(shí)一般使用如下
- [[UIApplication sharedApplication] sendAction: to: from: forEvent:];
 
響應(yīng)者鏈
在cocoa中所有響應(yīng)用戶輸入的對(duì)象都是抽象類NSResponder的子類
當(dāng)用戶處理應(yīng)用程序時(shí),cocoa會(huì)自動(dòng)跟蹤用戶的焦點(diǎn)位于何處,當(dāng)前正在接收鍵盤輸入的窗口稱為"關(guān)鍵"窗口,當(dāng)前具有焦點(diǎn)的文檔稱為“主”文檔,主文檔關(guān)聯(lián)的窗口稱為“主”窗口,在cocoa中應(yīng)用程序會(huì)自動(dòng)追蹤關(guān)鍵窗口和主窗口,下面的方法分別獲得引用
- [[UIApplication sharedApplication] keyWindow];//iphone
 - [[NSApplication sharedApplication] mainWindow] ;//macos
 
調(diào)用
大部分人都認(rèn)為selector與消息名稱是一回事,實(shí)際上不完全是,selector沒(méi)有提供任何類型信息,當(dāng)需要構(gòu)造一個(gè)消息的時(shí)候就需要知道每個(gè)參數(shù)的類型和返回值的類型,這種類型信息就稱為方法簽名(method signature)。
NSMethodSignature類封裝了這種信息,使用示例如下
- MyDocument *mydoc;
 - NSMethodSignature *mySig=[mydoc methodSignatureForSelector:@selector(window:shouldDragDocumentWithEvent:from:withPasteboard:) ];
 
使用NSInvocation可以發(fā)送消息,創(chuàng)建它的實(shí)例,配置后可以多次使用,并獲得返回值 ,具體的實(shí)例就不寫了,參考下面的網(wǎng)址吧
http://www.cnblogs.com/chenjunbiao/archive/2011/04/20/2022197.html
享元
享元用來(lái)封裝非對(duì)象數(shù)據(jù),使得可以在上下文中使用,并且在需要大量實(shí)例時(shí),享元減少了存儲(chǔ)需求
如 NSNumber NSValue
NSDate;
- NSDecimalNumber;
 - NSDate;
 - NSCalendarDate;
 - NSString;
 - NSURL;
 - NSFileHandle;
 - NSPipe;
 - NSAffineTransform;
 
都是享元
NSColor ,NSFont;這些享元緩存并重用對(duì)象
[NSColor redColor];返回同一個(gè)共享實(shí)例,下一次請(qǐng)求還是用的同樣的一個(gè)實(shí)例
裝飾器 Decorator
就是對(duì)象之間的復(fù)合,減少類的數(shù)量, has-a
用于隱藏復(fù)雜性的模式
包
就是把資源雜七雜八的打包一起
獲得可執(zhí)行程序所在的包
- NSBundle *_budle=[NSBundle bundleForClass:[NSString class]];
 
動(dòng)態(tài)加載可執(zhí)行代碼
- NSSearchPathForDirectoriesInDomains //函數(shù)可以獲取所有的包路徑
 - _budle=[NSBundle bundleWithPath:@"路徑"];//動(dòng)態(tài)加載包
 - BOOL isLoaded=[_budle load];//強(qiáng)制包的可執(zhí)行代碼鏈接進(jìn)應(yīng)用程序中
 - id class1=[_budle classNamed:@"類名"];//訪問(wèn)包中的類
 
類簇
Class Cluster模式給復(fù)雜的底層實(shí)現(xiàn)提供了一個(gè)簡(jiǎn)單的接口
類簇的主要?jiǎng)訖C(jī)就是為了屏蔽內(nèi)部實(shí)現(xiàn)的復(fù)雜性,盡量提供簡(jiǎn)單的接口
類簇模式利用的技術(shù)依賴于cocoa的兩階段創(chuàng)建模式,兩階段即內(nèi)存分配與初始化
利用兩階段創(chuàng)建,首先從+alloc 返回指向未初始化的新實(shí)例的存儲(chǔ)空間指針,然后利用-(id)init方法的某個(gè)遍體初始化新實(shí)例
因此通過(guò)init返回的可能就是公共接口的某個(gè)子類的實(shí)例,在init方法中首先要釋放掉已經(jīng)分配的抽象基礎(chǔ)類的實(shí)例,然后創(chuàng)建可以返回的想要的具體的子類的實(shí)例。
類簇的方式提供了簡(jiǎn)單的接口,但是復(fù)雜化了子類的創(chuàng)建
管理者模式
顧名思義管理者就是管理其他類的實(shí)例的類,cocoa中的NSFileManager NSFontManager NSInputManager NSLayoutManager
在應(yīng)用程序設(shè)計(jì)中通常具有一個(gè)對(duì)象的集合,這些對(duì)象需要是唯一的,但是他們并不是單例
例如字體,字體可以有多種不同的字體,但是同一個(gè)字體在系統(tǒng)中有一個(gè)實(shí)例就夠了
小結(jié):Cocoa學(xué)習(xí)筆記 設(shè)計(jì)模式詳解的內(nèi)容介紹完了,希望本文對(duì)你有所幫助!















 
 
 
 
 
 
 