引用:
無(wú)論一個(gè)類設(shè)計(jì)的多么完美,在未來(lái)的需求演進(jìn)中,都有可能會(huì)碰到一些無(wú)法預(yù)測(cè)的情況。那怎么擴(kuò)展已有的類呢?一般而言,繼承和組合是不錯(cuò)的選擇。但是在Objective-C 2.0中,又提供了category這個(gè)語(yǔ)言特性,可以動(dòng)態(tài)地為已有類添加新行為。如今category已經(jīng)遍布于Objective-C代碼的各個(gè)角落,從Apple官方的framework到各個(gè)開源框架,從功能繁復(fù)的大型APP到簡(jiǎn)單的應(yīng)用,catagory無(wú)處不在
兩種類型:
-
1
eg:著名的MJRefresh
普通的分類.png
-
2 class-continuation 分類(其實(shí)不能算是分類,緊緊是private的作用)
eg:
注意事項(xiàng):
-
命名:如果分類方法的命名和類中方法名相同則實(shí)際是覆蓋(并不是真正意義上的覆蓋,詳情可以看文章末尾推薦的文章)了類中的方法,所以命名很重要,如著名的SDWebImage UIImageView的分類 方法名均以sd_打頭
SDWebImage.png - 實(shí)例變量可以放到class-continuation 分類中,也可以放到實(shí)現(xiàn)文件中,個(gè)人建議放到
class-continuation 分類,因?yàn)楹退接袑傩?、方法放一起?huì)更清晰一些
作用:
- 她可以為任何類添加新的方法,包括那些沒有源代碼的類,無(wú)需創(chuàng)建對(duì)象類的子類就能完成同樣的工作
- 將類的實(shí)現(xiàn)代碼分散到便于管理的數(shù)個(gè)分類中,這樣會(huì)清晰很多
- 便于調(diào)試,call stack(回溯信息中)查看較方便
- 私有方法放入class-continuation 分類中隱藏細(xì)節(jié)(雖然不是真正的私有但是這樣做是可以隱藏很多不需要調(diào)用人知道的細(xì)節(jié))
- 關(guān)聯(lián)對(duì)象 (MJRefresh就是這樣做的)可參考iOS之category
- 屬性:只讀狀態(tài)可以擴(kuò)充為可讀寫 不直接訪問(wèn)實(shí)例變量 而是通過(guò)設(shè)置方法訪問(wèn)來(lái)做 因?yàn)檫@樣可以觸發(fā)KVO,外部既不能修改,內(nèi)部又可以按需求管理數(shù)據(jù)
下面寫個(gè)demo具體解釋,還是以Student類為例
@interface Student : NSObject
@property (nonatomic,copy,readonly) NSString *firstName; // 這里設(shè)為只讀,不想外部改動(dòng)
@property (nonatomic,copy,readonly) NSString *lastName;
- (instancetype)initWithFirstName:(NSString*)firstName lastName:(NSString*)lastName;
@end
#import "Student.h"
@interface Student()
@property (nonatomic,copy,readwrite) NSString *firstName;
@property (nonatomic,copy,readwrite) NSString *lastName;
// 這邊可以寫方法原型,方法的聲明
- (void)p_do1;
- (void)p_do2;
- (void)p_do3;
@end
@implementation Student
#pragma mark - life circle
- (instancetype)initWithFirstName:(NSString*)firstName lastName:(NSString*)lastName {
if (self = [super init]) {
_firstName = [firstName copy];
_lastName = [lastName copy];
}
return self;
}
- (void)dealloc {
NSLog(@"%s",__func__);
}
#pragma mark - public method
#pragma mark - private method
- (void)p_do1 {
self.firstName = @"john";
}
- (void)p_do2 {
}
- (void)p_do3 {
}
@end
@interface Student (Study)
- (void)ttt_study;
- (void)ttt_studyEnglish;
@end
#import "Student+Study.h"
@implementation Student (Study)
- (void)ttt_study {
}
- (void)ttt_studyEnglish {
// 這里故意寫一個(gè)數(shù)組越界的情況為了解釋分類調(diào)試方便
NSArray* arr = @[];
NSObject* obj = arr[1];
NSLog(@"study english");
}
@end
@interface Student (Play)
- (void)ttt_play;
- (void)ttt_playLOL;
@end
Play的實(shí)現(xiàn)就不粘上來(lái)了
如上所示:
- Student類有兩個(gè)屬性均為只讀,還有一個(gè)快捷初始化方法,在實(shí)現(xiàn)文件中我們將兩個(gè)只讀屬性擴(kuò)展為可讀可寫這樣就可以調(diào)用其set方法,觸發(fā)KVO
- 我這邊創(chuàng)建了兩個(gè)Student分類,如果Student類的方法非常龐大,我們就可以以這種方式將各個(gè)不同功能的方法進(jìn)行分類,減小文件大小使類更加清晰;方法名均已ttt打頭,這是為了避免與原類中方法重名導(dǎo)致覆蓋,也借鑒了優(yōu)秀代碼SDWebImage的命名習(xí)慣
- 我在 class-continuation 分類聲明了三個(gè)方法,以p_打頭是為了告訴自己,這是一個(gè)私有方法,當(dāng)然也可以不用先聲明,直接實(shí)現(xiàn)即可,但是這種方式讓我隔斷時(shí)間再次看這樣的類的時(shí)候就會(huì)很快明白這個(gè)類是要干嘛的
- 關(guān)于調(diào)試:使用分類可以更快速的定位到錯(cuò)誤,上面例子中的call stack
極力推薦:
希望會(huì)給大家?guī)?lái)幫助 O(∩_∩)O