ios-Runtime学习篇

一、基础知识

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 

@protocol KeyValue 

@optional
/**
 *  数组中需要转换的模型类
 *
 *  @return 字典中的key是数组属性名,value是数组中存放模型的Class(Class类型或者NSString类型)
 */
+ (NSDictionary *)objectClassInArray;

/**
 *  将属性名换为其他key去字典中取值
 *
 *  @return 字典中的key是属性名,value是从字典中取值用的key
 */
+ (NSDictionary *)replacedKeyFromPropertyName;

@end

@interface NSObject (Property) 

+ (instancetype)objectWithDictionary:(NSDictionary *)dictionary;

.m中的实现

#import "NSObject+Property.h"
#import 

@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

动态添加属性
1.第一种

#import "Person.h"
@interface Person (PersonExtention)
@property (copy, nonatomic) NSString *name;
-(void)saySex;
@end
#import "Person+PersonExtention.h"
#import 
@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学习篇)