在OC中可以通過Category給類添加屬性、方法、協(xié)議。
本文不介紹怎樣添加屬性、方法和協(xié)議,我們來分析一個相關問題:如果有多個Categroy中添加的方法和原類的方法重復定義,那么方法調(diào)用的行為是怎樣的呢?原理是怎樣的?
定義一個Person類以及兩個Person類的分類
@interface CLPerson : NSObject
- (void)work;
@end
@implementation CLPerson
- (void)work {
NSLog(@"class = %@ | method = %s", [CLPerson class],__func__);
}
@end
@interface CLPerson (Method)
- (void)work;
@end
@implementation CLPerson (Method)
- (void)work {
NSLog(@"class = %@ | method = %s", [CLPerson class],__func__);
}
@end
@interface CLPerson (Method2)
- (void)work;
@end
@implementation CLPerson (Method2)
- (void)work {
NSLog(@"class = %@ | method = %s", [CLPerson class],__func__);
}
@end
調(diào)用Person類的work方法。
CLPerson *person = [[CLPerson alloc]init];
[person work];
輸出結果:
CategoryTest[44899:3185760] class = CLPerson | method = -[CLPerson(Method2) work]
從輸出結果我們可以看出,調(diào)用了Method2分類的work方法。
結論:方法調(diào)用會優(yōu)先選擇Category的方法。
那么為什么不是調(diào)用Method分類的work方法呢?
原因是:Category和原類的方法都會被添加到方法列表中,只是方法存在的順序不同。

從圖中可以看出,Method2分類是排列在Method分類之后的,所以調(diào)用的是Method2的work方法。
結論:按照Category被添加到項目中的排列順序,后面被添加的Category會被優(yōu)先調(diào)用。
如果是系統(tǒng)的類是否會遵循這個規(guī)則?當然會遵循。
定義一個NSString的分類,實現(xiàn)一個NSString已有的方法。此處以stringByAppendingString:為示例。
@interface NSString (CLTest)
- (NSString *)stringByAppendingString:(NSString *)aString;
@end
@implementation NSString (CLTest)
- (NSString *)stringByAppendingString:(NSString *)aString {
return self;
}
@end
NSString *str = @"Hello World!";
NSLog(@"after appending str = %@", [str stringByAppendingString:@"Hello World 2!"]);
輸出結果:
CategoryTest[45579:3224464] after appending str = Hello World!
從輸出結果我們可以看出,Hello World 2!并沒有被追加到原字符串后面。
結論:系統(tǒng)方法被Category中定義的方法覆蓋掉了。
下面我們來對這些結論做一個總結。
總結:
- 方法調(diào)用的時候優(yōu)先遍歷Category的方法。
- 如果有多個Category,后面被添加到項目里的Category會被優(yōu)先調(diào)用。
- 如果從方法列表中找到方法后,就不會繼續(xù)向后查找。
根據(jù)上文對Category方法覆蓋調(diào)用行為規(guī)則的總結,下面我們來對這些規(guī)則的原理做一個簡要的分析。
原理分析:
- 原類是在編譯期就直接編譯好的,而Category是在運行時動態(tài)地添加到原類中的。
- 那么,在類的方法列表中,原類的方法一定是早于Category的方法被添加。
- Category是按照文件加載順序被添加到原類中的。
- 方法調(diào)用的時候,后被添加的方法,會先被遍歷到,而一旦方法被找到,就會停止遍歷。
這就是原類方法會被Category方法覆蓋,并且優(yōu)先選擇排列在最后Category的原因了。