美文网首页
ios-Runtime学习篇

ios-Runtime学习篇

作者: 命运建筑师fly | 来源:发表于2017-09-01 07:15 被阅读0次
    一、基础知识

    Method :成员方法

    Ivar : 成员变量

    二、常用方法

    class_copyPropertyList : 获取属性列表

    class_copyMethodList : 获取成员方法列表

    class_copyIvarList:获取成员变量列表

    ivar_getName:获取变量名

    property_getName:获取属性名

    使用示例:

    1.获取成员变量列表

    //1.获取变量list
            unsigned int ivarCount = 0; //成员变量数
            Ivar *ivarList = class_copyIvarList([self class], &ivarCount);//ivar数组
            
            for (int i = 0; i < ivarCount; i++) {//遍历
                Ivar ivar = ivarList[i]; //获取ivar
                const char *name = ivar_getName(ivar);//获取变量名
                NSString *key = [NSString stringWithUTF8String:name];
                NSLog(@"%@", key);
    
            }
    
          free(ivarList);
    

    2.获取属性列表

    unsigned int count = 0;
        objc_property_t *propertList = class_copyPropertyList([self class], &count);
        for (int i = 0; i < count; i++) {
            objc_property_t property = propertList[i];
            const char *name = property_getName(property);
            const char *attrs = property_getAttributes(property);
    //        property_copyAttributeValue(,) 第一个参数为objc_property_t,第二个参数"V"获取变量名,"T"获取类型
            const char *value = property_copyAttributeValue(property, "V");
            NSLog(@"name = %s, attrs = %s, value = %s", name, attrs, value);
        }
        free(propertList);
    

    3.获取方法列表

    unsigned int count = 0;
        Method *methodList = class_copyMethodList([self class], &count);
        for (int i = 0 ; i < count; i++) {
            Method method = methodList[i];
            SEL selector = method_getName(method);//方法入口
            const char *sel_name = sel_getName(selector);
            NSLog(@"方法名 %s", sel_name);
        }
        free(methodList);
    
    实用

    1.交换方法
    新建分类,在实现+ (void)load 在加载时候交换

    + (void)load
    {
    //说明class_getInstanceMethod获取实例方法,class_getClassMethod获取类方法
        static dispatch_once_t onceToken;
        dispatch_once(&onceToken, ^{
            Method method1 = class_getInstanceMethod(self, NSSelectorFromString(@"dealloc"));
            Method method2 = class_getInstanceMethod(self, @selector(my_dealloc));
            method_exchangeImplementations(method1, method2);
        });
    }
    
    - (void)my_dealloc
    {
        NSLog(@"%@销毁了", self);
        [self my_dealloc];
    }
    

    2、字典转模型

    .h中

    #import <Foundation/Foundation.h>
    
    @protocol KeyValue <NSObject>
    
    @optional
    /**
     *  数组中需要转换的模型类
     *
     *  @return 字典中的key是数组属性名,value是数组中存放模型的Class(Class类型或者NSString类型)
     */
    + (NSDictionary *)objectClassInArray;
    
    /**
     *  将属性名换为其他key去字典中取值
     *
     *  @return 字典中的key是属性名,value是从字典中取值用的key
     */
    + (NSDictionary *)replacedKeyFromPropertyName;
    
    @end
    
    @interface NSObject (Property) <KeyValue>
    
    + (instancetype)objectWithDictionary:(NSDictionary *)dictionary;
    

    .m中的实现

    #import "NSObject+Property.h"
    #import <objc/runtime.h>
    
    @implementation NSObject (Property)
    
    + (instancetype)objectWithDictionary:(NSDictionary *)dictionary
    {
        id obj = [[self alloc] init];
    
        // 获取所有的成员变量
        unsigned int count;
        Ivar *ivars = class_copyIvarList(self, &count);
    
        for (unsigned int i = 0; i < count; i++)
        {
            Ivar ivar = ivars[i];
    
            // 取出的成员变量,去掉下划线
            NSString *ivarName = [NSString stringWithUTF8String:ivar_getName(ivar)];
            NSString *key = [ivarName substringFromIndex:1];
    
            id value = dictionary[key];
    
            // 当这个值为空时,判断一下是否执行了replacedKeyFromPropertyName协议,如果执行了替换原来的key查值
            if (!value)
            {
                if ([self respondsToSelector:@selector(replacedKeyFromPropertyName)])
                {
                    NSString *replaceKey = [self replacedKeyFromPropertyName][key];
                    value = dictionary[replaceKey];
                }
            }
    
            // 字典嵌套字典
            if ([value isKindOfClass:[NSDictionary class]])
            {
                NSString *type = [NSString stringWithUTF8String:ivar_getTypeEncoding(ivar)];
                NSRange range = [type rangeOfString:@"\""];
                type = [type substringFromIndex:range.location + range.length];
                range = [type rangeOfString:@"\""];
                type = [type substringToIndex:range.location];
                Class modelClass = NSClassFromString(type);
    
                if (modelClass)
                {
                    value = [modelClass objectWithDictionary:value];
                }
            }
    
            // 字典嵌套数组
            if ([value isKindOfClass:[NSArray class]])
            {
                if ([self respondsToSelector:@selector(objectClassInArray)])
                {
                    NSMutableArray *models = [NSMutableArray array];
    
                    NSString *type = [self objectClassInArray][key];
                    Class classModel = NSClassFromString(type);
                    for (NSDictionary *dict in value)
                    {
                        id model = [classModel objectWithDictionary:dict];
                        [models addObject:model];
                    }
                    value = models;
                }
            }
    
            if (value)
            {
                [obj setValue:value forKey:key];
            }
        }
        
        // 释放ivars
        free(ivars);
    
        return obj;
    }
    
    @end
    

    实用案例

    subcategories 数组中装的SubCategoryModel类
    + (NSDictionary *)objectClassInArray
    {
        return @{ @"subcategories": @"SubCategoryModel"};
    }
    
    foodId 来替换关键字id
    + (NSDictionary *)replacedKeyFromPropertyName
    {
        return @{ @"foodId": @"id" };
    }
    
    /* 获取对象的所有属性 */
    +(NSArray *)getAllProperties
    {
        u_int count;
        // 传递count的地址过去 &count
        objc_property_t *properties  =class_copyPropertyList([self class], &count);
        //arrayWithCapacity的效率稍微高那么一丢丢
        NSMutableArray *propertiesArray = [NSMutableArray arrayWithCapacity:count];
    
        for (int i = 0; i < count ; i++)
        {
            //此刻得到的propertyName为c语言的字符串
            const char* propertyName =property_getName(properties[i]);
            //此步骤把c语言的字符串转换为OC的NSString
            [propertiesArray addObject: [NSString stringWithUTF8String: propertyName]];
        }
        //class_copyPropertyList底层为C语言,所以我们一定要记得释放properties
        // You must free the array with free().
        free(properties);
    
        return propertiesArray;
    }
    
    
    
    /* 获取对象的所有方法 */
    +(NSArray *)getAllMethods
    {
        unsigned int methodCount =0;
        Method* methodList = class_copyMethodList([self class],&methodCount);
        NSMutableArray *methodsArray = [NSMutableArray arrayWithCapacity:methodCount];
    
        for(int i=0;i<methodCount;i++)
        {
            Method temp = methodList[i];
            IMP imp = method_getImplementation(temp);
            SEL name_f = method_getName(temp);
            const char* name_s =sel_getName(method_getName(temp));
            int arguments = method_getNumberOfArguments(temp);
            const char* encoding =method_getTypeEncoding(temp);
            NSLog(@"方法名:%@,参数个数:%d,编码方式:%@",[NSString stringWithUTF8String:name_s],
                  arguments,
                  [NSString stringWithUTF8String:encoding]);
            [methodsArray addObject:[NSString stringWithUTF8String:name_s]];
        }
        free(methodList);
        return methodsArray;
    }
    
    
    /* 获取对象的所有属性和属性内容 */
    + (NSDictionary *)getAllPropertiesAndVaules:(NSObject *)obj
    {
        NSMutableDictionary *propsDic = [NSMutableDictionary dictionary];
        unsigned int outCount;
        objc_property_t *properties =class_copyPropertyList([obj class], &outCount);
        for ( int i = 0; i<outCount; i++)
        {
            objc_property_t property = properties[i];
            const char* char_f =property_getName(property);
            NSString *propertyName = [NSString stringWithUTF8String:char_f];
            id propertyValue = [obj valueForKey:(NSString *)propertyName];
            if (propertyValue) {
                [propsDic setObject:propertyValue forKey:propertyName];
            }
        }
        free(properties);
        return propsDic;
    }
    
    @end
    
    

    动态添加属性
    1.第一种

    #import "Person.h"
    @interface Person (PersonExtention)
    @property (copy, nonatomic) NSString *name;
    -(void)saySex;
    @end
    #import "Person+PersonExtention.h"
    #import <objc/runtime.h>
    @implementation Person (PersonExtention)
    //定义常量 必须是C语言字符串
    static char *PersonNameKey = "PersonNameKey";
    -(void)setName:(NSString *)name{
        /*
        OBJC_ASSOCIATION_ASSIGN;            //assign策略
        OBJC_ASSOCIATION_COPY_NONATOMIC;    //copy策略
        OBJC_ASSOCIATION_RETAIN_NONATOMIC;  // retain策略
    
        OBJC_ASSOCIATION_RETAIN;
        OBJC_ASSOCIATION_COPY;
         */
         /*
         * id object 给哪个对象的属性赋值
           const void *key 属性对应的key
           id value  设置属性值为value
           objc_AssociationPolicy policy  使用的策略,是一个枚举值,和copy,retain,assign是一样的,手机开发一般都选择NONATOMIC
              objc_setAssociatedObject(id object, const void *key, id value, objc_AssociationPolicy policy);
         */
    
        objc_setAssociatedObject(self, PersonNameKey, name, OBJC_ASSOCIATION_COPY_NONATOMIC);
    }
    -(NSString *)name{
        return objc_getAssociatedObject(self, PersonNameKey);
    }
    -(void)saySex{
        NSLog(@"%s----%@",__func__,self);
    }
    
    @end
    

    2.第二种

    
    @interface UIViewController (EZBackPop)
    
    @property (nonatomic, assign) BOOL isAutorotate;
    
    @end
    
    
    - (BOOL)isAutorotate
    {
        return [objc_getAssociatedObject(self, _cmd) boolValue];
    }
    
    - (void)setIsAutorotate:(BOOL)isAutorotate
    {
        objc_setAssociatedObject(self, @selector(isAutorotate), @(isAutorotate), OBJC_ASSOCIATION_ASSIGN);
    }
    

    3.第三种

    
    @interface UIButton (sswAddType)
    
    @property(nonatomic, assign) int type;
    @end
    
    - (void)setType:(int)type{
        objc_setAssociatedObject(self, "type", @(type), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
    }
    
    - (int)type{
        
        return [objc_getAssociatedObject(self, "type") intValue];
    }
    

    相关文章

      网友评论

          本文标题:ios-Runtime学习篇

          本文链接:https://www.haomeiwen.com/subject/kpwcjxtx.html