Objective-C類別也叫分類妨马,是一種不需要繼承即可給類添加方法的語(yǔ)法技術(shù)。下面我們來(lái)看看如何使用它,以及使用的三種場(chǎng)景弟翘。
添加類別
類別聲明模板:
h文件:
@interface ClassName (XSD_CategoryName)
- (void)xsd_addedMethod;
@end
m文件:
@implementation ClassName (XSD_CategoryName)
- (void)xsd_addedMethod {
}
@end
XSD
是我自定義的前綴,強(qiáng)烈建議都加上一個(gè)自定義的前綴骄酗,原因后面詳細(xì)敘述稀余。
通過(guò)Xcode8添加
類別的使用三種場(chǎng)景
1. 擴(kuò)展已有的類
說(shuō)到給已有的類添加方法趋翻,似乎應(yīng)該定義一個(gè)子類睛琳,繼承已有的類,然后添加方法,比如我們常常會(huì)自定義UITableViewCell师骗,XSDTableviewCell, showIconWithImage:(UIImage *)image,
但現(xiàn)實(shí)情況往往是茁影,大量已有的代碼,都已經(jīng)使用父類UITableViewCell實(shí)現(xiàn)丧凤,使用子類需要
- 添加新類的頭文件
- 所有用
UITableViewCell
的地方要改為XSDTableviewCell
- 調(diào)用新方法
showIconWithImage:
這第二步募闲,可能涉及數(shù)組存儲(chǔ)、參數(shù)愿待、局部變量等多個(gè)地方的類名修改浩螺,如果修改的方法需要跨文件共用,會(huì)花費(fèi)大量時(shí)間仍侥。
這時(shí)用類別要出,就變?yōu)椋?/p>
- 添加新類別的頭文件
- 用UITableViewCell直接調(diào)用新類別方法
另外,如果已經(jīng)存在使用XSDTableviewCell的地方农渊,也只需要引入新類別的頭文件患蹂,就可以直接調(diào)用showIconWithImage:
方法了,因?yàn)?lt;u>添加到父類中類別方法砸紊,會(huì)被子類繼承</u>传于。
因此,
類別特別適合已經(jīng)存在大量子類醉顽,需要添加公用方法沼溜,但又無(wú)法修改它們父類(如系統(tǒng)類)的情形
2. 引用父類未公開(kāi)方法
比如父類 XSDLabel:
// XSDLabel.h
#import <UIKit/UIKit.h>
@interface XSDLabel : UILabel
@end
// XSDLabel.m
#import "XSDLabel.h"
@implementation XSDLabel
- (void)giveTextRandomColor {
self.textColor = [UIColor orangeColor];
}
@end
XSDLabel1繼承自XSDLabel:
#import <UIKit/UIKit.h>
#import "XSDLabel.h"
@interface XSDLabel1 : XSDLabel
@end
現(xiàn)在需要在設(shè)置text時(shí),同時(shí)設(shè)置文字顏色游添,調(diào)用父類的giveTextRandomColor:
#import "XSDLabel1.h"
@implementation XSDLabel1
- (void)setText:(NSString *)text {
[super setText:text];
[self giveTextRandomColor];
}
@end
直接編譯會(huì)報(bào)錯(cuò):
在子類中聲明父類類別后系草,即可通過(guò)編譯:
#import "XSDLabel1.h"
@interface XSDLabel (private)
- (void)giveTextRandomColor;
@end
@implementation XSDLabel1
- (void)setText:(NSString *)text {
[super setText:text];
[self giveTextRandomColor];
}
@end
類別名private
是任意的,但不可以缺省唆涝。
請(qǐng)不要亂來(lái):蘋果官方會(huì)拒絕使用系統(tǒng)私有API的應(yīng)用上架找都,因此即使學(xué)會(huì)了如何調(diào)用私有方法,在遇到調(diào)用其它類的私有方法時(shí)廊酣,要謹(jǐn)慎處理能耻,盡量用其它方法替代。
3. 實(shí)現(xiàn)簡(jiǎn)單協(xié)議
假設(shè)我們需要在文字顏色改變時(shí)啰扛,發(fā)出一個(gè)消息嚎京,現(xiàn)在修改XSDLabel如下:
#import <UIKit/UIKit.h>
@interface XSDLabel : UILabel
@property(nonatomic) id delegate;
@end
@interface NSObject (XSDLabelDelegateMethods)
- (void)textColorChanged:(UIColor *)colorNow;
@end
增加delegate,聲明為id隐解,表示接受任何類鞍帝。
聲明NSObject的類別,聲明它實(shí)現(xiàn)的方法煞茫。
#import "XSDLabel.h"
@implementation XSDLabel
- (void)giveTextRandomColor {
self.textColor = [UIColor orangeColor];
[self.delegate textColorChanged:self.textColor]; // 調(diào)用代理的方法
}
@end
調(diào)用的地方:
#import "XSDLabel1.h"
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
XSDLabel1 *label = [[XSDLabel1 alloc] initWithFrame:CGRectMake(10.0, 40.0, 100.0, 30.0)];
[self.view addSubview:label];
label.delegate = self;
label.text = @"溪石iOS";
}
- (void)textColorChanged:(UIColor *)colorNow {
NSLog(@"text color changed to %@", colorNow);
}
這里利用了任何類都是NSObject子類的特點(diǎn)帕涌,通過(guò)添加NSObject的類別摄凡,實(shí)現(xiàn)了一個(gè)“簡(jiǎn)單”的代理協(xié)議。
對(duì)比“正式的協(xié)議”蚓曼,這種協(xié)議不需要實(shí)現(xiàn)類顯示聲明(如<NSCopying>)亲澡,不過(guò)這里還有個(gè)缺點(diǎn),當(dāng)ViewController未實(shí)現(xiàn)textColorChanged方法時(shí)纫版,會(huì)引發(fā)崩潰床绪,因此在調(diào)用前,需要檢查代理方法是否被實(shí)現(xiàn):
#import "XSDLabel.h"
@implementation XSDLabel
- (void)giveTextRandomColor {
self.textColor = [UIColor orangeColor];
if ([self.delegate respondsToSelector:@selector(textColorChanged:)]) {
[self.delegate textColorChanged:self.textColor];
}
}
@end
類別的局限
- 只能添加方法其弊,不能添加屬性癞己。在類別中聲明的屬性,將無(wú)法存取梭伐。
- 類別中的方法痹雅,會(huì)覆蓋父類中的同名方法,無(wú)法再調(diào)用父類中的方法(因?yàn)轭悇e中無(wú)法使用super)糊识,為防止意外覆蓋绩社,總是應(yīng)該給類別加上前綴。
- 不同文件中的同名類別赂苗,同名方法愉耙,不會(huì)報(bào)錯(cuò),實(shí)際執(zhí)行的方法以最后一個(gè)加載的文件為準(zhǔn)哑梳,因此使用前綴防止類別人互相覆蓋劲阎。
小結(jié)
本文給出了添加類別的方法,Xcode8添加類別的方式與前幾代有所不同鸠真。
接著介紹了類別使用的三種情形:
- 擴(kuò)展已有的類。
- 引用父類未公開(kāi)方法龄毡。
- 實(shí)現(xiàn)簡(jiǎn)單協(xié)議吠卷。
最后介紹了類別的局限,主要是存儲(chǔ)空間的分配和名稱沖突沦零,后者可以用加前綴的方式最大限度的避免祭隔。
類別是充分利用Objective-C動(dòng)態(tài)特性的一種方法,用好類別可以實(shí)現(xiàn)靈活多樣的編碼路操。