通过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 = [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获取对象相关信息

 

 

 

 

 

 

 

 

你可能感兴趣的:(Runtime)