通过runtime获取对象相关信息
在这里,本人给大家提供一个runtime关于NSObject的扩展,用来显示各种NSObject中的信息,这有助于你来分析类的组成:)
先准备以下类供测试:
Model.h 与 Model.m
// // Model.h // Runtime // // Copyright (c) 2014年 Y.X. All rights reserved. // #import <Foundation/Foundation.h>typedef enum : NSUInteger {male,female, } ModelSex;@interface Model : NSObject@property (nonatomic, strong) NSString *name; @property (nonatomic, strong) NSNumber *age; @property (nonatomic, assign) ModelSex sex;- (void)info; + (void)className;@end
// // Model.m // Runtime // // Copyright (c) 2014年 Y.X. All rights reserved. // #import "Model.h"@implementation Model- (void)info {NSLog(@"info"); }+ (void)className {NSLog(@"Model"); }@end
以下是NSObject关于runtime的扩展category
NSObject+Runtime.h 与 NSObject+Runtime.m
// // NSObject+Runtime.h // Runtime // // Copyright (c) 2014年 Y.X. All rights reserved. // #import <Foundation/Foundation.h>@interface NSObject (Runtime)/* ------------------------------------ */ // 获取当前类所有的子类 + (NSArray *)runtimeSubClasses; - (NSArray *)runtimeSubClasses;// 获取当前类所有的父类继承关系 + (NSString *)runtimeParentClassHierarchy; - (NSString *)runtimeParentClassHierarchy; /* ------------------------------------ *//* ------------------------------------ */ // 获取当前类类方法 + (NSArray *)runtimeClassMethods; - (NSArray *)runtimeClassMethods;// 获取当前类实例方法 + (NSArray *)runtimeInstanceMethods; - (NSArray *)runtimeInstanceMethods; /* ------------------------------------ *//* ------------------------------------ */ // 获取当前类实例变量大小 + (size_t)runtimeInstanceSize; - (size_t)runtimeInstanceSize;// 获取当前类的所有属性 + (NSArray *)runtimeProperties; - (NSArray *)runtimeProperties; /* ------------------------------------ */// 获取当前类继承的所有协议 + (NSArray *)runtimeProtocols; - (NSArray *)runtimeProtocols;@end
// // NSObject+Runtime.m // Runtime // // Copyright (c) 2014年 Y.X. All rights reserved. // #import "NSObject+Runtime.h" #import <objc/runtime.h>static void getSuper(Class class, NSMutableString *result) {[result appendFormat:@" -> %@", NSStringFromClass(class)];if ([class superclass]) { getSuper([class superclass], result); } }@interface NSString (Runtime) + (NSString *)decodeType:(const char *)cString; @end@implementation NSString (Runtime)+ (NSString *)decodeType:(const char *)cString {if (!strcmp(cString, @encode(id))) return @"id";if (!strcmp(cString, @encode(void))) return @"void";if (!strcmp(cString, @encode(float))) return @"float";if (!strcmp(cString, @encode(int))) return @"int";if (!strcmp(cString, @encode(BOOL))) return @"BOOL";if (!strcmp(cString, @encode(char *))) return @"char *";if (!strcmp(cString, @encode(double))) return @"double";if (!strcmp(cString, @encode(Class))) return @"class";if (!strcmp(cString, @encode(SEL))) return @"SEL";if (!strcmp(cString, @encode(unsigned int))) return @"unsigned int";NSString *result = [NSString stringWithCString:cString encoding:NSUTF8StringEncoding];if ([[result substringToIndex:1] isEqualToString:@"@"] && [result rangeOfString:@"?"].location == NSNotFound) {result = [[result substringWithRange:NSMakeRange(2, result.length - 3)] stringByAppendingString:@"*"];} elseif ([[result substringToIndex:1] isEqualToString:@"^"]) {result = [NSString stringWithFormat:@"%@ *",[NSString decodeType:[[result substringFromIndex:1] cStringUsingEncoding:NSUTF8StringEncoding]]];}return result; }@end@implementation NSObject (Runtime)- (NSArray *)runtimeProperties {return [[self class] runtimeProperties]; }+ (NSArray *)runtimeProperties {unsigned int outCount;objc_property_t *properties = class_copyPropertyList([self class], &outCount);NSMutableArray *result = [NSMutableArray array];for (int i = 0; i < outCount; i++) {[result addObject:[self formattedPropery:properties[i]]];}free(properties);return result.count ? [result copy] : nil; }- (NSString *)runtimeParentClassHierarchy {return [[self class] runtimeParentClassHierarchy]; }+ (NSString *)runtimeParentClassHierarchy {NSMutableString *result = [NSMutableString string];getSuper([self class], result);return result; }- (NSArray *)runtimeSubClasses {return [[self class] runtimeSubClasses]; }+ (NSArray *)runtimeSubClasses {Class *buffer = NULL;int count, size;do{count = objc_getClassList(NULL, 0);buffer = (Class *)realloc(buffer, count * sizeof(*buffer));size = objc_getClassList(buffer, count);} while(size != count);NSMutableArray *array = [NSMutableArray array];for(int i = 0; i < count; i++){Class candidate = buffer[i];Class superclass = candidate;while(superclass){if(superclass == self){[array addObject: candidate];break;}superclass = class_getSuperclass(superclass);}}free(buffer);return array; }- (size_t)runtimeInstanceSize {return [[self class] runtimeInstanceSize]; }+ (size_t)runtimeInstanceSize {return class_getInstanceSize(self); }- (NSArray *)runtimeClassMethods {return [[self class] runtimeClassMethods]; }+ (NSArray *)runtimeClassMethods {return [self methodsForClass:object_getClass([self class]) typeFormat:@"+"]; }- (NSArray *)runtimeInstanceMethods {return [[self class] runtimeInstanceMethods]; }+ (NSArray *)runtimeInstanceMethods {return [self methodsForClass:[self class] typeFormat:@"-"]; }- (NSArray *)runtimeProtocols {return [[self class] runtimeProtocols]; }+ (NSArray *)runtimeProtocols {unsigned int outCount;Protocol * const *protocols = class_copyProtocolList([self class], &outCount);NSMutableArray *result = [NSMutableArray array];for (int i = 0; i < outCount; i++) {unsigned int adoptedCount;Protocol * const *adotedProtocols = protocol_copyProtocolList(protocols[i], &adoptedCount);NSString *protocolName = [NSString stringWithCString:protocol_getName(protocols[i]) encoding:NSUTF8StringEncoding];NSMutableArray *adoptedProtocolNames = [NSMutableArray array];for (int idx = 0; idx < adoptedCount; idx++) {[adoptedProtocolNames addObject:[NSString stringWithCString:protocol_getName(adotedProtocols[idx]) encoding:NSUTF8StringEncoding]];}NSString *protocolDescription = protocolName;if (adoptedProtocolNames.count) {protocolDescription = [NSString stringWithFormat:@"%@ <%@>", protocolName, [adoptedProtocolNames componentsJoinedByString:@", "]];}[result addObject:protocolDescription];//free(adotedProtocols); }//free((__bridge void *)(*protocols));return result.count ? [result copy] : nil; }#pragma mark - Private+ (NSArray *)methodsForClass:(Class)class typeFormat:(NSString *)type {unsigned int outCount;Method *methods = class_copyMethodList(class, &outCount);NSMutableArray *result = [NSMutableArray array];for (int i = 0; i < outCount; i++) {NSString *methodDescription = [NSString stringWithFormat:@"%@ (%@)%@",type,[NSString decodeType:method_copyReturnType(methods[i])],NSStringFromSelector(method_getName(methods[i]))];NSInteger args = method_getNumberOfArguments(methods[i]);NSMutableArray *selParts = [[methodDescription componentsSeparatedByString:@":"] mutableCopy];NSInteger offset = 2; //1-st arg is object (@), 2-nd is SEL (:)for (int idx = offset; idx < args; idx++) {NSString *returnType = [NSString decodeType:method_copyArgumentType(methods[i], idx)];selParts[idx - offset] = [NSString stringWithFormat:@"%@:(%@)arg%d",selParts[idx - offset],returnType,idx - 2];}[result addObject:[selParts componentsJoinedByString:@" "]];}free(methods);return result.count ? [result copy] : nil; }+ (NSArray *)formattedMethodsForProtocol:(Protocol *)proto required:(BOOL)required instance:(BOOL)instance {unsigned int methodCount;struct objc_method_description *methods = protocol_copyMethodDescriptionList(proto, required, instance, &methodCount);NSMutableArray *methodsDescription = [NSMutableArray array];for (int i = 0; i < methodCount; i++) {[methodsDescription addObject:[NSString stringWithFormat:@"%@ (%@)%@",instance ? @"-" : @"+", @"void",NSStringFromSelector(methods[i].name)]];}free(methods);return [methodsDescription copy]; }+ (NSString *)formattedPropery:(objc_property_t)prop {unsigned int attrCount;objc_property_attribute_t *attrs = property_copyAttributeList(prop, &attrCount);NSMutableDictionary *attributes = [NSMutableDictionary dictionary];for (int idx = 0; idx < attrCount; idx++) {NSString *name = [NSString stringWithCString:attrs[idx].name encoding:NSUTF8StringEncoding];NSString *value = [NSString stringWithCString:attrs[idx].value encoding:NSUTF8StringEncoding];[attributes setObject:value forKey:name];}free(attrs);NSMutableString *property = [NSMutableString stringWithFormat:@"@property "];NSMutableArray *attrsArray = [NSMutableArray array];//https://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/ObjCRuntimeGuide/Articles/ocrtPropertyIntrospection.html#//apple_ref/doc/uid/TP40008048-CH101-SW5[attrsArray addObject:[attributes objectForKey:@"N"] ? @"nonatomic" : @"atomic"];if ([attributes objectForKey:@"&"]) {[attrsArray addObject:@"strong"];} else if ([attributes objectForKey:@"C"]) {[attrsArray addObject:@"copy"];} else if ([attributes objectForKey:@"W"]) {[attrsArray addObject:@"weak"];} else {[attrsArray addObject:@"assign"];}if ([attributes objectForKey:@"R"]) {[attrsArray addObject:@"readonly"];}if ([attributes objectForKey:@"G"]) {[attrsArray addObject:[NSString stringWithFormat:@"getter=%@", [attributes objectForKey:@"G"]]];}if ([attributes objectForKey:@"S"]) {[attrsArray addObject:[NSString stringWithFormat:@"setter=%@", [attributes objectForKey:@"G"]]];}[property appendFormat:@"(%@) %@ %@",[attrsArray componentsJoinedByString:@", "],[NSString decodeType:[[attributes objectForKey:@"T"] cStringUsingEncoding:NSUTF8StringEncoding]],[NSString stringWithCString:property_getName(prop) encoding:NSUTF8StringEncoding]];return [property copy]; }@end
以下是使用情形:
// // AppDelegate.m // Runtime // // Copyright (c) 2014年 Y.X. All rights reserved. // #import "AppDelegate.h" #import "NSObject+Runtime.h" #import "Model.h"@implementation AppDelegate- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {NSLog(@"%@", [Model runtimeClassMethods]);NSLog(@"%@", [Model runtimeInstanceMethods]);NSLog(@"%@", [Model runtimeProperties]);NSLog(@"%@", [Model runtimeParentClassHierarchy]);NSLog(@"%@", [Model runtimeSubClasses]);return YES; }@end
打印信息如下:
Runtime[43597:60b] (
"+ (void)className"
)
Runtime[43597:60b] (
"- (id)age",
"- (void)setAge:(id)arg0 ",
"- (unsigned int)sex",
"- (void)setSex:(unsigned int)arg0 ",
"- (void)setName:(id)arg0 ",
"- (void).cxx_destruct",
"- (id)name",
"- (void)info"
)
Runtime[43597:60b] (
"@property (nonatomic, strong) NSString* name",
"@property (nonatomic, strong) NSNumber* age",
"@property (nonatomic, assign) unsigned int sex"
)
Runtime[43597:60b] -> Model -> NSObject
Runtime[43597:60b] (
Model
)
以下是一些注意一点的地方:
每一个类均有一个类方法和实例变量方法相互对应