引用:
無論一個類設計的多么完美,在未來的需求演進中,都有可能會碰到一些無法預測的情況。那怎么擴展已有的類呢?一般而言,繼承和組合是不錯的選擇。但是在Objective-C 2.0中,又提供了category這個語言特性,可以動態(tài)地為已有類添加新行為。如今category已經遍布于Objective-C代碼的各個角落,從Apple官方的framework到各個開源框架,從功能繁復的大型APP到簡單的應用,catagory無處不在
兩種類型:
-
1
eg:著名的MJRefresh

普通的分類.png
-
2 class-continuation 分類(其實不能算是分類,緊緊是private的作用)
eg:

注意事項:
-
命名:如果分類方法的命名和類中方法名相同則實際是覆蓋(并不是真正意義上的覆蓋,詳情可以看文章末尾推薦的文章)了類中的方法,所以命名很重要,如著名的SDWebImage UIImageView的分類 方法名均以sd_打頭
SDWebImage.png - 實例變量可以放到class-continuation 分類中,也可以放到實現文件中,個人建議放到
class-continuation 分類,因為和私有屬性、方法放一起會更清晰一些
作用:
- 她可以為任何類添加新的方法,包括那些沒有源代碼的類,無需創(chuàng)建對象類的子類就能完成同樣的工作
- 將類的實現代碼分散到便于管理的數個分類中,這樣會清晰很多
- 便于調試,call stack(回溯信息中)查看較方便
- 私有方法放入class-continuation 分類中隱藏細節(jié)(雖然不是真正的私有但是這樣做是可以隱藏很多不需要調用人知道的細節(jié))
- 關聯對象 (MJRefresh就是這樣做的)可參考iOS之category
- 屬性:只讀狀態(tài)可以擴充為可讀寫 不直接訪問實例變量 而是通過設置方法訪問來做 因為這樣可以觸發(fā)KVO,外部既不能修改,內部又可以按需求管理數據
下面寫個demo具體解釋,還是以Student類為例
@interface Student : NSObject
@property (nonatomic,copy,readonly) NSString *firstName; // 這里設為只讀,不想外部改動
@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 {
// 這里故意寫一個數組越界的情況為了解釋分類調試方便
NSArray* arr = @[];
NSObject* obj = arr[1];
NSLog(@"study english");
}
@end
@interface Student (Play)
- (void)ttt_play;
- (void)ttt_playLOL;
@end
Play的實現就不粘上來了
如上所示:
- Student類有兩個屬性均為只讀,還有一個快捷初始化方法,在實現文件中我們將兩個只讀屬性擴展為可讀可寫這樣就可以調用其set方法,觸發(fā)KVO
- 我這邊創(chuàng)建了兩個Student分類,如果Student類的方法非常龐大,我們就可以以這種方式將各個不同功能的方法進行分類,減小文件大小使類更加清晰;方法名均已ttt打頭,這是為了避免與原類中方法重名導致覆蓋,也借鑒了優(yōu)秀代碼SDWebImage的命名習慣
- 我在 class-continuation 分類聲明了三個方法,以p_打頭是為了告訴自己,這是一個私有方法,當然也可以不用先聲明,直接實現即可,但是這種方式讓我隔斷時間再次看這樣的類的時候就會很快明白這個類是要干嘛的
- 關于調試:使用分類可以更快速的定位到錯誤,上面例子中的call stack

極力推薦:
希望會給大家?guī)韼椭?O(∩_∩)O
