Objective-C類別也叫分類,是一種不需要繼承即可給類添加方法的語法技術。下面我們來看看如何使用它,以及使用的三種場景。
添加類別
類別聲明模板:
h文件:
@interface ClassName (XSD_CategoryName)
- (void)xsd_addedMethod;
@end
m文件:
@implementation ClassName (XSD_CategoryName)
- (void)xsd_addedMethod {
}
@end
XSD是我自定義的前綴,強烈建議都加上一個自定義的前綴,原因后面詳細敘述。
通過Xcode8添加





類別的使用三種場景
1. 擴展已有的類
說到給已有的類添加方法,似乎應該定義一個子類,繼承已有的類,然后添加方法,比如我們常常會自定義UITableViewCell,XSDTableviewCell, showIconWithImage:(UIImage *)image,
但現實情況往往是,大量已有的代碼,都已經使用父類UITableViewCell實現,使用子類需要
- 添加新類的頭文件
- 所有用
UITableViewCell的地方要改為XSDTableviewCell - 調用新方法
showIconWithImage:
這第二步,可能涉及數組存儲、參數、局部變量等多個地方的類名修改,如果修改的方法需要跨文件共用,會花費大量時間。
這時用類別,就變?yōu)椋?/p>
- 添加新類別的頭文件
- 用UITableViewCell直接調用新類別方法
另外,如果已經存在使用XSDTableviewCell的地方,也只需要引入新類別的頭文件,就可以直接調用showIconWithImage:方法了,因為<u>添加到父類中類別方法,會被子類繼承</u>。
因此,
類別特別適合已經存在大量子類,需要添加公用方法,但又無法修改它們父類(如系統(tǒng)類)的情形
2. 引用父類未公開方法
比如父類 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
現在需要在設置text時,同時設置文字顏色,調用父類的giveTextRandomColor:
#import "XSDLabel1.h"
@implementation XSDLabel1
- (void)setText:(NSString *)text {
[super setText:text];
[self giveTextRandomColor];
}
@end
直接編譯會報錯:

在子類中聲明父類類別后,即可通過編譯:
#import "XSDLabel1.h"
@interface XSDLabel (private)
- (void)giveTextRandomColor;
@end
@implementation XSDLabel1
- (void)setText:(NSString *)text {
[super setText:text];
[self giveTextRandomColor];
}
@end
類別名private是任意的,但不可以缺省。
請不要亂來:蘋果官方會拒絕使用系統(tǒng)私有API的應用上架,因此即使學會了如何調用私有方法,在遇到調用其它類的私有方法時,要謹慎處理,盡量用其它方法替代。
3. 實現簡單協議
假設我們需要在文字顏色改變時,發(fā)出一個消息,現在修改XSDLabel如下:
#import <UIKit/UIKit.h>
@interface XSDLabel : UILabel
@property(nonatomic) id delegate;
@end
@interface NSObject (XSDLabelDelegateMethods)
- (void)textColorChanged:(UIColor *)colorNow;
@end
增加delegate,聲明為id,表示接受任何類。
聲明NSObject的類別,聲明它實現的方法。
#import "XSDLabel.h"
@implementation XSDLabel
- (void)giveTextRandomColor {
self.textColor = [UIColor orangeColor];
[self.delegate textColorChanged:self.textColor]; // 調用代理的方法
}
@end
調用的地方:
#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子類的特點,通過添加NSObject的類別,實現了一個“簡單”的代理協議。
對比“正式的協議”,這種協議不需要實現類顯示聲明(如<NSCopying>),不過這里還有個缺點,當ViewController未實現textColorChanged方法時,會引發(fā)崩潰,因此在調用前,需要檢查代理方法是否被實現:
#import "XSDLabel.h"
@implementation XSDLabel
- (void)giveTextRandomColor {
self.textColor = [UIColor orangeColor];
if ([self.delegate respondsToSelector:@selector(textColorChanged:)]) {
[self.delegate textColorChanged:self.textColor];
}
}
@end
類別的局限
- 只能添加方法,不能添加屬性。在類別中聲明的屬性,將無法存取。
- 類別中的方法,會覆蓋父類中的同名方法,無法再調用父類中的方法(因為類別中無法使用super),為防止意外覆蓋,總是應該給類別加上前綴。
- 不同文件中的同名類別,同名方法,不會報錯,實際執(zhí)行的方法以最后一個加載的文件為準,因此使用前綴防止類別人互相覆蓋。
小結
本文給出了添加類別的方法,Xcode8添加類別的方式與前幾代有所不同。
接著介紹了類別使用的三種情形:
- 擴展已有的類。
- 引用父類未公開方法。
- 實現簡單協議。
最后介紹了類別的局限,主要是存儲空間的分配和名稱沖突,后者可以用加前綴的方式最大限度的避免。
類別是充分利用Objective-C動態(tài)特性的一種方法,用好類別可以實現靈活多樣的編碼。