首页 > 代码库 > 通过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获取对象相关信息