反射再構成コードの使用(OC)
10514 ワード
ぜんせん
OCのruntimeはJavaで反射する概念です.OCにおけるruntimeの応用はとっくにぼろぼろになっているが,今日は送信による再構成コードの例を紹介する.まず2つの関数を紹介し,機能はそれぞれ以下の通りである.プロトコルに準拠するすべてのクラス(RMClassThatConformsToProtocol) を取得あるクラスを継承するすべてのクラス(RMClassesThatBaseClass) を取得する
実現構想.
プロトコルを遵守するすべてのクラスを取得は、反射機構を利用して、登録されたすべてのクラスの個数を取得する. Classクラスのサイズに応じて、対応するメモリサイズが割り当てられます. 反射機構を利用して、すべてのクラスを取得する. すべてのクラスを遍歴し、あるプロトコルを遵守するクラスを探し出して配列 に参加する.
再構築前には126行のコードがあり、クラスを1つ追加するたびに、対応する登録を手動で追加することがわかり、2つの問題が発生しました.コードは冗長で、多くの重複コードがあります. は登録の追加を忘れがちです.
すべてのHandlerオブジェクトはRMHandlerから継承され、RMHandlerはstartメソッドが各Handlerオブジェクトを呼び出す機能を提供するので、Handlerのようなメソッドは書き換えられ、対応する機能が実現される.このようにフレームワークすることで,上のコードに対してpathパラメータのみが一致しない.その他はほとんど重複するコードです.
構想を再構築する.
再構築はすぐにできるものではありません.コードを書けば書くほど、上記の登録方法は大きく異なり、pathパラメータだけが異なることがわかります.このとき、再構築を考えて、この重複コードを抽出しなければなりません.私が提供した2つの関数機能を使用すると、すべてのRMHandlerオブジェクトがRMHandlerから継承されるため、反射を利用してすべてのRMHandlerオブジェクトを取得し、統一インタフェースを提供し、各クラスがそれぞれの機能に基づいてインタフェースを再書き込みすることができます.再構築されたコードは以下のように,16行しかないが,上記と同様の機能を実現し,容易に拡張できる.
OCのruntimeはJavaで反射する概念です.OCにおけるruntimeの応用はとっくにぼろぼろになっているが,今日は送信による再構成コードの例を紹介する.まず2つの関数を紹介し,機能はそれぞれ以下の通りである.
実現構想.
プロトコルを遵守するすべてのクラスを取得
int numClasses = objc_getClassList(NULL, 0);
classes = (__unsafe_unretained Class*)malloc(sizeof(Class) * numClasses);
numClasses = objc_getClassList(classes, numClasses);
for (int index = 0; index < numClasses; index++) {
Class aClass = classes[index];
if (class_conformsToProtocol(aClass, protocol)) {
[collection addObject:aClass];
}
}
全体コード:NSArray *RMClassesThatConformsToProtocol(Protocol *protocol)
{
Class *classes = NULL;
NSMutableArray *collection = [NSMutableArray array];
int numClasses = objc_getClassList(NULL, 0);
if (numClasses == 0 ) {
return @[];
}
classes = (__unsafe_unretained Class*)malloc(sizeof(Class) * numClasses);
numClasses = objc_getClassList(classes, numClasses);
for (int index = 0; index < numClasses; index++) {
Class aClass = classes[index];
if (class_conformsToProtocol(aClass, protocol)) {
[collection addObject:aClass];
}
}
free(classes);
return collection.copy;
}
クラスを継承するすべてのクラスを取得NSArray *RMClassesThatBaseClass(Class baseClass)
{
Class *classes = NULL;
NSMutableArray *collection = [NSMutableArray array];
int numClasses = objc_getClassList(NULL, 0);
if (numClasses == 0 ) {
return @[];
}
NSString *bcls = NSStringFromClass(baseClass);
classes = (__unsafe_unretained Class*)malloc(sizeof(Class) * numClasses);
numClasses = objc_getClassList(classes, numClasses);
for (int index = 0; index < numClasses; index++) {
Class aClass = classes[index];
Class superClass = class_getSuperclass(aClass);
NSString *cls = NSStringFromClass(aClass);
if ([cls isEqualToString:bcls]) continue;
NSString *supercls = NSStringFromClass(superClass);
if ([supercls isEqualToString: bcls]) {
[collection addObject:aClass];
}
}
free(classes);
return collection.copy;
}
再構築前のコード再構築前には126行のコードがあり、クラスを1つ追加するたびに、対応する登録を手動で追加することがわかり、2つの問題が発生しました.
// register API
[_httpServer addHandlerForMethod:@"GET" path:@"/loadDriver" requestClass:[RMRequest class] processBlock:^GCDWebServerResponse *(__kindof GCDWebServerRequest *request) {
RMHandler *handler = [RMHandlerManager createHandlerWithRequest: request];
[handler start];
NSMutableDictionary *json = [NSMutableDictionary dictionary];
[json setObject:handler.sessionID forKey:kRMSessionIDKey];
[json setObject:request.query forKey:@"query"];
return [GCDWebServerDataResponse responseWithJSONObject:json];
}];
[_httpServer addHandlerForMethod:@"GET" path:@"/startApp" requestClass:[RMRequest class] processBlock:^GCDWebServerResponse *(__kindof GCDWebServerRequest *request) {
RMHandler *handler = [RMHandlerManager createHandlerWithRequest: request];
[handler start];
NSMutableDictionary *json = [NSMutableDictionary dictionary];
[json setObject:handler.sessionID forKey:kRMSessionIDKey];
[json setObject:request.query forKey:@"query"];
return [GCDWebServerDataResponse responseWithJSONObject:json];
}];
[_httpServer addHandlerForMethod:@"GET" path:@"/startMonkey" requestClass:[RMRequest class] processBlock:^GCDWebServerResponse *(__kindof GCDWebServerRequest *request) {
RMHandler *handler = [RMHandlerManager createHandlerWithRequest: request];
[handler start];
NSMutableDictionary *json = [NSMutableDictionary dictionary];
[json setObject:handler.sessionID forKey:kRMSessionIDKey];
[json setObject:request.query forKey:@"query"];
return [GCDWebServerDataResponse responseWithJSONObject:json];
}];
[_httpServer addHandlerForMethod:@"GET" path:@"/typeText" requestClass:[RMRequest class] processBlock:^GCDWebServerResponse *(__kindof GCDWebServerRequest *request) {
RMHandler *handler = [RMHandlerManager createHandlerWithRequest: request];
[handler start];
NSMutableDictionary *json = [NSMutableDictionary dictionary];
if (handler) {
[json setObject:handler.sessionID forKey:kRMSessionIDKey];
[json setObject:handler.result == nil?@{}:handler.result forKey:kRMQueryKey];
}else {
NSLog(@" ");
}
return [GCDWebServerDataResponse responseWithJSONObject:json];
}];
[_httpServer addHandlerForMethod:@"GET" path:@"/findElementsByClassname" requestClass:[RMRequest class] processBlock:^GCDWebServerResponse *(__kindof GCDWebServerRequest *request) {
RMHandler *handler = [RMHandlerManager createHandlerWithRequest: request];
[handler start];
NSMutableDictionary *json = [NSMutableDictionary dictionary];
if (handler) {
[json setObject:handler.sessionID forKey:kRMSessionIDKey];
[json setObject:handler.result == nil?@{}:handler.result forKey:kRMQueryKey];
}else {
NSLog(@" ");
}
return [GCDWebServerDataResponse responseWithJSONObject:json];
}];
[_httpServer addHandlerForMethod:@"GET" path:@"/clearText" requestClass:[RMRequest class] processBlock:^GCDWebServerResponse *(__kindof GCDWebServerRequest *request) {
RMHandler *handler = [RMHandlerManager createHandlerWithRequest: request];
[handler start];
NSMutableDictionary *json = [NSMutableDictionary dictionary];
if (handler) {
[json setObject:handler.sessionID forKey:kRMSessionIDKey];
[json setObject:handler.result == nil?@{}:handler.result forKey:kRMQueryKey];
}else {
NSLog(@" ");
}
return [GCDWebServerDataResponse responseWithJSONObject:json];
}];
// tap action
[_httpServer addHandlerForMethod:@"GET" path:@"/tap" requestClass:[RMRequest class] processBlock:^GCDWebServerResponse *(__kindof GCDWebServerRequest *request) {
RMHandler *handler = [RMHandlerManager createHandlerWithRequest: request];
[handler start];
NSMutableDictionary *json = [NSMutableDictionary dictionary];
if (handler) {
[json setObject:handler.sessionID forKey:kRMSessionIDKey];
[json setObject:handler.result == nil?@{}:handler.result forKey:kRMQueryKey];
}else {
NSLog(@" ");
}
return [GCDWebServerDataResponse responseWithJSONObject:json];
}];
// swipe action
[_httpServer addHandlerForMethod:@"GET" path:@"/swipe" requestClass:[RMRequest class] processBlock:^GCDWebServerResponse *(__kindof GCDWebServerRequest *request) {
RMHandler *handler = [RMHandlerManager createHandlerWithRequest: request];
[handler start];
NSMutableDictionary *json = [NSMutableDictionary dictionary];
if (handler) {
[json setObject:handler.sessionID forKey:kRMSessionIDKey];
[json setObject:handler.result == nil?@{}:handler.result forKey:kRMQueryKey];
}else {
NSLog(@" ");
}
return [GCDWebServerDataResponse responseWithJSONObject:json];
}];
// /inspector
[_httpServer addHandlerForMethod:@"GET" path:@"/inspector" requestClass:[RMRequest class] processBlock:^GCDWebServerResponse *(__kindof GCDWebServerRequest *request) {
RMHandler *handler = [RMHandlerManager createHandlerWithRequest: request];
[handler start];
NSMutableDictionary *json = [NSMutableDictionary dictionary];
if (handler) {
[json setObject:handler.sessionID forKey:kRMSessionIDKey];
[json setObject:handler.result == nil?@{}:handler.result forKey:kRMQueryKey];
}else {
NSLog(@" ");
}
return [GCDWebServerDataResponse responseWithJSONObject:json];
}];
バックグラウンドの再構築すべてのHandlerオブジェクトはRMHandlerから継承され、RMHandlerはstartメソッドが各Handlerオブジェクトを呼び出す機能を提供するので、Handlerのようなメソッドは書き換えられ、対応する機能が実現される.このようにフレームワークすることで,上のコードに対してpathパラメータのみが一致しない.その他はほとんど重複するコードです.
構想を再構築する.
再構築はすぐにできるものではありません.コードを書けば書くほど、上記の登録方法は大きく異なり、pathパラメータだけが異なることがわかります.このとき、再構築を考えて、この重複コードを抽出しなければなりません.私が提供した2つの関数機能を使用すると、すべてのRMHandlerオブジェクトがRMHandlerから継承されるため、反射を利用してすべてのRMHandlerオブジェクトを取得し、統一インタフェースを提供し、各クラスがそれぞれの機能に基づいてインタフェースを再書き込みすることができます.再構築されたコードは以下のように,16行しかないが,上記と同様の機能を実現し,容易に拡張できる.
// register
NSArray *handlersClasses = RMClassesThatBaseClass(RMHandler.class);
NSMutableArray *handlers = [NSMutableArray array];
for (Class aClass in handlersClasses) {
[_httpServer addHandlerForMethod:[aClass method] path:[aClass path] requestClass:[RMRequest class] processBlock:^GCDWebServerResponse *(__kindof GCDWebServerRequest *request) {
RMHandler *handler = [RMHandlerManager createHandlerWithRequest: request];
[handler start];
NSMutableDictionary *json = [NSMutableDictionary dictionary];
if (handler) {
[json setObject:handler.sessionID forKey:kRMSessionIDKey];
[json setObject:handler.result == nil?@{}:handler.result forKey:kRMQueryKey];
}else {
NSLog(@" ");
}
return [GCDWebServerDataResponse responseWithJSONObject:json];
}];
}