首页 > 代码库 > 通过runtime获取对象相关信息
通过runtime获取对象相关信息
通过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:@"*"]; } else if ([[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 =http://www.mamicode.com/ [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
)
以下是一些注意一点的地方:
每一个类均有一个类方法和实例变量方法相互对应
通过runtime获取对象相关信息