https://github.com/YouXianMing

通过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
)

以下是一些注意一点的地方:

每一个类均有一个类方法和实例变量方法相互对应

 

 

 

 

 

 

 

 
posted @ 2014-09-02 21:47  YouXianMing  阅读(603)  评论(0编辑  收藏  举报