分类(category)的使用
首先可以查看下官方對于Category的介紹:Apple官方文檔解釋
個人理解:
另類使用:
定義一個NSObject的分類Worker,通過@property聲明兩個屬性如下:
@interface NSObject (Worker) @property (nonatomic, copy) NSString *name; @property (nonatomic, copy) NSString *jodName; @end如果這時直接使用name和jodName如下:
NSObject *worker = [[NSObject alloc] init]; worker.name = @"Jim"; worker.jodName = @"Software Engineer";command+R運行則會報如下錯誤:
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[NSObject setName:]: unrecognized selector sent to instance 0x600001a7c570'這是因為系統不會給Category添加屬性的setter/getter方法,所以這時就要用到runtime機制了,寫法如下:
// name的key static NSString *keyName; // jobName的key static NSString *keyJobName;@implementation NSObject (Worker) - (void)setName:(NSString *)name {objc_setAssociatedObject(self, &keyName, name, OBJC_ASSOCIATION_COPY); } - (NSString *)name {return objc_getAssociatedObject(self, &keyName); } - (void)setJodName:(NSString *)jodName {objc_setAssociatedObject(self, &keyJobName, jodName, OBJC_ASSOCIATION_COPY); } - (NSString *)jodName {return objc_getAssociatedObject(self, &keyJobName); } @end在 setter 里面使用了一個 objc_setAssociatedObject(id _Nonnull object, const void * _Nonnull key, id _Nullable value, objc_AssociationPolicy policy) 方法,這個方法有四個參數,分別是:
在 getter 里面用到了 objc_getAssociatedObject(id _Nonnull object, const void * _Nonnull key) 這個方法,這個方法有兩個參數,填寫方法參照setter方法。
這時再運行代碼如下:
NSObject *worker = [[NSObject alloc] init]; worker.name = @"Jim"; worker.jodName = @"Software Engineer"; NSLog(@"Hello, my name is %@, I am a %@ !",worker.name,worker.jodName);打印信息如下:
2019-04-30 11:24:43.258099+0800 test[44759:2009573] Hello, my name is Jim, I am a Software Engineer !這樣就實現了在變相的在分類里添加了假屬性,注意:這種添加方式并不支持_name和_jobName的方式調用方式,因為真正意思上并沒有相關屬性
在分類中重寫了原類中的方法,在調用該方法時,程序是觸發的分類中重寫的方法,但有時我們還是需要用到原類中的方法,接下來就看下怎么用代碼實現:
先生成一個Person類,實現一個方法:
- (NSString *)getWorkerIntroducation {return @"該方法由分類實現的,返回的是這個人的介紹信息"; }在生成一個分類Person+Worker.h,重寫方法如下:
- (NSString *)getWorkerIntroducation {if (self.name.length&&self.jodName.length) {return [NSString stringWithFormat:@"My name is %@, I am a %@!", self.name, self.jodName];} else {return nil;} }在調用如下:
Person *worker = [[Person alloc] init]; worker.name = @"Jim"; worker.jodName = @"Software Engineer"; NSLog(@"%@", [worker getWorkerIntroducation]);打印日志:
2019-04-30 15:59:05.812732+0800 test[46479:2079803] My name is Jim, I am a Software Engineer!根據分類的原理,結構體中存在一個對象方法列表,主要就是通過獲取方法的列表實現調用原類的方法,我們可以先打印一下對象方法列表:
Person *worker = [[Person alloc] init]; worker.name = @"Jim"; worker.jodName = @"Software Engineer"; NSLog(@"%@", [worker getWorkerIntroducation]);// 打印對象方法列表 u_int count; Method *methods = class_copyMethodList([worker class], &count); for (int i=0; i<count; i++) {SEL sel = method_getName(methods[i]);NSString *methodName = [NSString stringWithCString:sel_getName(sel) encoding:NSUTF8StringEncoding];NSLog(@"%d = %@", i, methodName); } // 打印結果 // 調用分類重寫方法 My name is Jim, I am a Software Engineer! 0 = setJodName: // 分類的重寫方法 1 = getWorkerIntroducation // 原類的重寫方法 2 = getWorkerIntroducation 3 = jodName 4 = name 5 = setName:從打印信息來看分類的調用優先級是在前面的,所以需要遍歷獲取最后的方法再通過IMP調用,代碼如下:
Person *worker = [[Person alloc] init]; worker.name = @"Jim"; worker.jodName = @"Software Engineer"; NSLog(@"%@", [worker getWorkerIntroducation]);// 打印對象方法列表 u_int count; Method *methods = class_copyMethodList([worker class], &count); int index = -1; for (int i=0; i<count; i++) {SEL sel = method_getName(methods[i]);NSString *methodName = [NSString stringWithCString:sel_getName(sel) encoding:NSUTF8StringEncoding];if ([methodName isEqualToString:@"getWorkerIntroducation"]) {index = i;} } if (index>=0) {// 通過index獲取原類的方法SEL sel = method_getName(methods[index]);IMP imp = method_getImplementation(methods[index]);NSString *string = ((id (*)(id, SEL)) imp)(self, sel);NSLog(@"%@",string); } else {NSLog(@"不存在該方法"); }打印結果:
// 執行的分類方法 2019-04-30 17:21:50.688067+0800 test[49470:2130743] My name is Jim, I am a Software Engineer! // 執行的原類方法 2019-04-30 17:21:50.688238+0800 test[49470:2130743] 該方法由分類實現的,返回的是這個人的介紹信息代碼傳送門:
- 樣例代碼
傳送門:
- IMP原理介紹
- Category底層實現原理小記
總結
以上是生活随笔為你收集整理的分类(category)的使用的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 1901~2100年节气表
- 下一篇: idea破解到2100年