為什么使用類目
是一種為現(xiàn)有的類添加新方法的方式
有時(shí)需要對(duì)現(xiàn)有的類添加一些方法,之前都是通過繼承相關(guān)的類,然后再子類中擴(kuò)展我們需要的相應(yīng)的方法.
Objective-C是一種動(dòng)態(tài)語言,可以給現(xiàn)有的類添加新的方法,這便是對(duì)類目的延展.
類目(category):為已知的類添加新的方法,無論是否知道類的源代碼,這些類包括自己定義的類和系統(tǒng)已有的類。
類目的作用主要有三個(gè)方面:
1、將類的實(shí)現(xiàn)分散到多個(gè)不同的文件中,將多個(gè)類目的聲明放入同一個(gè).h文件中,將實(shí)現(xiàn)放入多個(gè).m方法中。
2、使用類目創(chuàng)建對(duì)私有方法的前向引用,就是為類創(chuàng)建私有方法。
3、向?qū)ο筇砑臃钦絽f(xié)議,現(xiàn)在逐漸被正式協(xié)議做替代。



類目的實(shí)現(xiàn)
類目聲明之后需要對(duì)類擴(kuò)展出來的方法進(jìn)行實(shí)現(xiàn)

使用擴(kuò)展后的方法
#import <Foundation/Foundation.h>
#import "NSString+MyNumber.h"http://添加類目頭文件
int main(int argc, const char * argv[])
{
@autoreleasepool
{
//創(chuàng)建四個(gè)字符串
NSString *str1=@"gdsfgsdfgfdgdfs";
NSString *str2=@"fgsagsdfgfdsg";
NSString *str3=@"打開分為飛大廈俄方飛";
NSString *str4=@"jfghjfghjfghj";
//求出每一個(gè)字符串的長(zhǎng)度
// int l1=(int)[str1 length];
// int l2=(int)[str2 length];
// int l3=(int)[str3 length];
// int l4=(int)[str4 length];
//
// //轉(zhuǎn)為對(duì)象
// NSNumber *m1=[NSNumber numberWithInt:l1];
// NSNumber *m2=[NSNumber numberWithInt:l2];
// NSNumber *m3=[NSNumber numberWithInt:l3];
// NSNumber *m4=[NSNumber numberWithInt:l4];
//創(chuàng)建一個(gè)可變的字典
NSMutableDictionary *mDic=[NSMutableDictionary new];
//添加對(duì)象到字典中
// [mDic setObject:m1 forKey:str1];
// [mDic setObject:m2 forKey:str2];
// [mDic setObject:m3 forKey:str3];
// [mDic setObject:m4 forKey:str4];
//使用類目后修改為
[mDic setObject:[str1 getStrLength] forKey:str1];
[mDic setObject:[str2 getStrLength] forKey:str2];
[mDic setObject:[str3 getStrLength] forKey:str3];
[mDic setObject:[str4 getStrLength] forKey:str4];
//輸出
NSLog(@"%@",mDic);
}
return 0;
}
注意類目里面只能寫方法,不能寫聲明和屬性,所以,類目不能作為接口來用
類目的局限性
-類目無法向已有類中添加實(shí)例變量
-如果類目中的方法和已有類中的方法名稱沖突時(shí),類目中的方法優(yōu)先級(jí)高,如果方法名沖突,已有類中的原始方法便無法使用
-在使用類目的時(shí)候,最好是將自己擴(kuò)展的方法和原始方法區(qū)分開來
類目的作用
有三個(gè)方面:
1.將類的實(shí)現(xiàn)分散到多個(gè)不同的文件中
-將多個(gè)類目的聲明放入同一個(gè).h文件中
-將實(shí)現(xiàn)放入多個(gè).m方法中
2.使用類目創(chuàng)建對(duì)私有方法的前向引用
-就是為類創(chuàng)建私有方法
3.向?qū)ο筇砑臃钦絽f(xié)議
-現(xiàn)在逐漸被正式協(xié)議做替代
利用類目分散實(shí)現(xiàn)類
-類的@implementation部分只能寫在一個(gè).m文件中
-對(duì)于大型的類,可以使用類目將類的實(shí)現(xiàn)間接的放入多個(gè).m文件中
-將多個(gè)類目的聲明放入同一個(gè).h文件中,包括多個(gè)類目聲明的@interface和@end
類私有的方法
-Objective-C中沒有絕對(duì)意義上的私有方法
-在.h文件中聲明的方法都屬于公開的方法,意味著開放給別人調(diào)用
-如果不想公開某些方法,可以不在.h文件中聲明
-這樣的方法可以被本類中的其他方法所調(diào)用
-如果在類外面強(qiáng)行調(diào)用這些未公開的方法,也能調(diào)用,但是會(huì)有編譯器警告
類的延展
延展(extension):
在自己類的實(shí)現(xiàn)文件中添加類目(匿名類目)來聲明私有方法.(只有本類的.m文件中才能使用)
類的延展可以讓類方法成為類的私有方法
將私有方法聲明到一個(gè)匿名類目中,并且將這個(gè)匿名類目放到類的.m文件里
然后在類的.m的@implementation部分將這個(gè)匿名類目中的私有方法進(jìn)行實(shí)現(xiàn)
這樣的也能夠?qū)懗鏊接蟹椒ǎ峭瑯右部梢詮?qiáng)行在類外部調(diào)用,也會(huì)有編譯器警告
使用類目對(duì)私有方法反向引用
-如果私有方法的聲明放入一個(gè)匿名類目中,并且這個(gè)類目放入一個(gè).h文件中那么這個(gè).h文件可以看做私有的API
-私有API可以不公開,只開放給許可者來調(diào)用
然后在使用私有API時(shí)將那個(gè).h文件導(dǎo)入,然后調(diào)用私有方法,編譯器警告便會(huì)消失
respondsToSelector
用來檢查某一個(gè)對(duì)象能否調(diào)用某一個(gè)方法(檢查方法時(shí)候有實(shí)現(xiàn))
創(chuàng)建了NSObject的類目之后,類目中聲明方法對(duì)于NSObject的子類來說如何檢查是否實(shí)現(xiàn)了哪個(gè)方法
因?yàn)榭赡芤{(diào)用某個(gè)NSObject類目中聲明的方法,在調(diào)用時(shí)需要判斷是否能夠響應(yīng)才行,否則會(huì)造成程序崩潰
MyClass *mc= [MyClass new];
if([mc respondsToSelector:@selector(test)])
{
[mc test];
}
else
{
NSLog(@"未實(shí)現(xiàn)test方法!");
}
Objective-C中的協(xié)議
協(xié)議是一個(gè)方法列表,采用協(xié)議時(shí)需要在聲明類時(shí)說明要采用的協(xié)議
協(xié)議的聲明
協(xié)議就是一種標(biāo)準(zhǔn),用來定義了實(shí)現(xiàn)什么,不關(guān)心具體怎么實(shí)現(xiàn)
OC的協(xié)議是由@protocol聲明的一組方法列表
要求其它的類去實(shí)現(xiàn),相當(dāng)于@interface部分的聲明
@required標(biāo)注的方法為必須實(shí)現(xiàn)方法(默認(rèn)不寫為必須實(shí)現(xiàn))
@optional標(biāo)注的方法為可以選擇實(shí)現(xiàn)
@protocol 協(xié)議名稱
//方法列表
@end
協(xié)議的實(shí)現(xiàn)
方式:
接口文件 一個(gè)類可以通過協(xié)議,用來遵循多個(gè)類中的方法,這樣可以做到多繼承的效果
@interface ClassName : 父類名 <協(xié)議1,協(xié)議2…>
@end
實(shí)現(xiàn)文件
@implementation ClassName
//實(shí)現(xiàn)協(xié)議中的方法
@end
具體實(shí)現(xiàn)方法
@protocol MyProtocol <NSObject>
@required//必須實(shí)現(xiàn)
-(int) addX:(int) x andY:(int) y;
@optional//可選實(shí)現(xiàn)
-(int) substructX:(int) x andY:(int) y;
@end
協(xié)議和數(shù)據(jù)類型
聲明實(shí)例變量或方法可以指定協(xié)議名稱
id類型可以指向任何類型的
@interface MyClass
{
id<MyProtocol> myVar;
}
@end
要求傳入的參數(shù)必須采用MyProtocol協(xié)議
-(void) methodName:(id<MyProtocol>) obj
{
//方法代碼
}
檢查對(duì)象是否實(shí)現(xiàn)了某個(gè)協(xié)議
可以通過對(duì)象的下列方法來判斷是否遵循某協(xié)議(confrorms:遵守)
conformsToProtocol:@protocol (協(xié)議名)
在此創(chuàng)建一個(gè)代理使用的實(shí)例
先創(chuàng)建兩個(gè)類,繼承NSObjective
一個(gè)被代理的類,命名為HouseMan
一個(gè)代理的類,命名Medium
HouseMan.h接口文件中實(shí)現(xiàn)
// 房東
#import <Foundation/Foundation.h>
//1.聲明協(xié)議
@protocol GetHoseProtocol <NSObject>
-(void)getRent;//房租的方法
@end
@interface HouseMan : NSObject
//2.創(chuàng)建一個(gè)代理人的屬性 在此簽訂一個(gè)協(xié)議
@property(nonatomic,assign)id<GetHoseProtocol> delegate;
//3.協(xié)議的方法
-(void)houseRent;
@end
HouseMan.m實(shí)現(xiàn)文件中實(shí)現(xiàn)
//4.實(shí)現(xiàn)需要代理的方法
-(void)houseRent
{
[self.delegate getRent];//呼叫被代理人去做
}
Medium.h接口文件中實(shí)現(xiàn)
#import <Foundation/Foundation.h>
#import "HouseMan.h"http://5.包含代理人的頭文件
@interface Medium : NSObject<GetHoseProtocol>//6.被代理人和代理人簽訂協(xié)議
//7聲明代理人的屬性
@property (nonatomic, strong) NSString *name;
Medium.m實(shí)現(xiàn)文件中
#import "Medium.h"
@implementation Medium
//7.實(shí)現(xiàn)被代理人的方法
-(void)getRent
{
NSLog(@"正在收房租");
}
@end
最后在main.m文件中
#import <Foundation/Foundation.h>
//包含頭文件
#import "HouseMan.h"
#import "Medium.h"
int main(int argc, const char * argv[])
{
@autoreleasepool
{
//創(chuàng)建代理對(duì)象
Medium *m=[Medium new];
m.name=@"房屋中介";
//創(chuàng)建被代理對(duì)象
HouseMan *h=[HouseMan new];
//給代理對(duì)象賦值
h.delegate=m;
//被代理人呼叫代理人實(shí)現(xiàn)方法 這個(gè)方法是在被代理人種實(shí)現(xiàn)的
[h houseRent];
}
return 0;
}
設(shè)計(jì)模式
設(shè)計(jì)模式(Design pattern)是一套被反復(fù)使用、多數(shù)人知曉的、經(jīng)過分類編目的、代碼設(shè)計(jì)經(jīng)驗(yàn)的總結(jié)。
-設(shè)計(jì)模式是某個(gè)具體編程問題的通用化,可以復(fù)用的解決方案
-沒有一種可以從前一個(gè)方案中完全復(fù)用代碼的情況,但是可以使用前一次的解決問題時(shí)使用的思想
-設(shè)計(jì)模式可以在遇到編程問題時(shí)會(huì)想起一個(gè)正確的解決方案
-常見的設(shè)計(jì)模式有:?jiǎn)卫J?、委?代理)模式、觀察者模式、職責(zé)鏈模式等等
委托模式
在委托模式中,程序中的一個(gè)對(duì)象代表另外一個(gè)對(duì)象執(zhí)行某個(gè)動(dòng)作,或者與之相互協(xié)作共同完成某個(gè)任務(wù)。
Cocoa Touch廣泛使用委托(delegate),它是負(fù)責(zé)為其他對(duì)象處理特定任務(wù)的類。通過委托,我們能夠在某些預(yù)定義時(shí)間內(nèi)為發(fā)布委托的類做一些工作。
所謂代理,就是指一方授予他方代理權(quán),他方依代理權(quán)與第三方進(jìn)行法律行為,其行為后果由一方承擔(dān)的一種民事法律制度。委托是一方將一定的事務(wù)委諸于另一方實(shí)施的法律制度。
委托和代理的區(qū)別:
第一,委托規(guī)范的是委托人和受托人雙方之間的關(guān)系;而代理規(guī)范的是本人、代理人和第三人的關(guān)系。
第二,代理關(guān)系中代理人代理的對(duì)象是進(jìn)行意思表示和接受意思表示的行為;而委托中受托人代為實(shí)施的行為可以是法律行為,也可以是事實(shí)行為。
第三,代理包括對(duì)內(nèi)和對(duì)外兩種關(guān)系,對(duì)內(nèi)是代理人和被代理人之間的關(guān)系,而對(duì)外是代理人和第三人之間的關(guān)系;而委托只是委托人和受托人之間的關(guān)系。
簡(jiǎn)單的總結(jié):
-委托就是有兩個(gè)對(duì)象,一個(gè)變化時(shí),另外一個(gè)能夠知道上面一個(gè)的變化.
-一個(gè)對(duì)象保存另外一個(gè)對(duì)象的引用,被引用的對(duì)象實(shí)現(xiàn)事先確定的協(xié)議,這個(gè)協(xié)議用來把對(duì)象中的變化通知給被引用的對(duì)象
-委托不一定使用到協(xié)議,使用類目一樣能完成,或者協(xié)議類目都不知用,同樣能做到.
delegate屬性都是assign而不是retain為了避免循環(huán)引用造成的內(nèi)存泄露。
循環(huán)引用的問題這樣理解:
-比如在main函數(shù)中創(chuàng)建了兩個(gè)類的對(duì)象A和B,現(xiàn)在引用計(jì)數(shù)都是1?,F(xiàn)在讓A和B互相引用(A有一個(gè)屬性是B對(duì)象,屬性說明是retain;B有一個(gè)屬性是A對(duì)象,屬性說明是retain),現(xiàn)在兩個(gè)對(duì)象的引用計(jì)數(shù)都增加了1,都變成了2。
-現(xiàn)在執(zhí)行 [A release]; [B release]; 此時(shí)創(chuàng)建對(duì)象的main函數(shù)已經(jīng)釋放了自己對(duì)對(duì)象的所有權(quán),但是此時(shí)A和B的引用計(jì)數(shù)都還是1,因?yàn)樗麄兓ハ嘁昧恕?br> -這時(shí)你發(fā)現(xiàn)A和B將無法釋放,因?yàn)橐脶尫臕必須先釋放B,在B的dealloc方法中再釋放A。同理,要想釋放B必須先釋放A,在A的dealloc方法中再釋放B。所以這兩個(gè)對(duì)象將一直存在在內(nèi)存中而不釋放。這就是所謂的循環(huán)引用的問題。
-要想解決這個(gè)問題,一般的方法可以將引用的屬性設(shè)置為assign,而不是retain來處理。
使用非正式協(xié)議的委托模式