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

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

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

     
  • 相关阅读:
    全网最新iOS面试题-大厂加薪篇
    iOS面试--虎牙最新iOS开发面试题
    iOS面试--字节跳动最新iOS开发面试题
    去面试腾讯iOS开发要达到咋样的水准?
    “iOS开发” 金三银四如何快速技术晋升?
    突破瓶颈,“iOS开发”,跳槽面试必备题(针对年后面试者)
    解决visio对象在word中显示不全的问题
    word中图片自动编号的交叉引用出现被引用的图片
    elasticsearch 一个分布式多用户能力的全文搜索引擎
    Maven仓库安装配置及使用
  • 原文地址:https://www.cnblogs.com/YouXianMing/p/3951276.html
Copyright © 2020-2023  润新知