美文网首页oc基础
iOS探究 --- Runtime的使用场景

iOS探究 --- Runtime的使用场景

作者: 空空_Jiminy | 来源:发表于2020-04-14 16:45 被阅读0次

    一,字典转模型

    经典的第三方库MJExtension
    https://www.jianshu.com/p/9b0b7cbc1d3c

    二,无侵入埋点(系统方法替换)

    https://www.jianshu.com/p/735d45745d87

    三,访问私有变量

    两种方式
    1.KVC
    2.Runtime
    这里只实现runtime

    Person定义如下
    Person.h

    @interface Person : NSObject
    
    - (void)printName;
    
    @end
    

    Person.m

    @interface Person()
    
    @property (nonatomic, copy) NSString *name;
    @property (nonatomic) NSInteger age;
    
    
    @end
    
    @implementation Person
    
    - (void)printName {
        NSLog(@"name === %@", self.name);
    }
    
    @end
    
    

    ViewController

    - (void)viewDidLoad {
        [super viewDidLoad];
        
        Person *person = [Person new];
        [self changePersonName:person name:@"newName"];
        [person printName];
    }
    
    - (void)changePersonName:(Person *)person name:(NSString *)name {
        
        unsigned int count = 0;
        
        Ivar *ivars = class_copyIvarList(objc_getClass("Person"), &count);
        
        for (int i = 0; i<count; i++) {
            Ivar ivar = ivars[I];
            NSString *ivarName = [[NSString alloc] initWithUTF8String:ivar_getName(ivar)];
            if ([ivarName isEqualToString:@"_name"]) {
                object_setIvar(person, ivar, name);
            }
        }
        
        free(ivars);
    }
    

    打印结果


    image.png

    四,category中添加属性

    为刚才的Person类增加一个Category


    image.png

    我们发现,在.h文件里,是可以增加nickName属性。
    但是当我们调用的时候会崩溃。原因是set和get并未实现。


    image.png
    这是就需要我们用到Runtime来添加set和get方法了。
    - (void)setNickName:(NSString *)nickName {
        
        /*
         objc_AssociationPolicy参数使用的策略:
         OBJC_ASSOCIATION_ASSIGN;            //assign策略
         OBJC_ASSOCIATION_COPY_NONATOMIC;    //copy策略
         OBJC_ASSOCIATION_RETAIN_NONATOMIC;  // retain策略
    
         OBJC_ASSOCIATION_RETAIN;
         OBJC_ASSOCIATION_COPY;
         */
        /*
         关联方法:
         objc_setAssociatedObject(id object, const void *key, id value, objc_AssociationPolicy policy);
    
         参数:
         * id object 给哪个对象的属性赋值
         const void *key 属性对应的key
         id value  设置属性值为value
         objc_AssociationPolicy policy  使用的策略,是一个枚举值,和copy,retain,assign是一样的,手机开发一般都选择NONATOMIC
         */
        
        objc_setAssociatedObject(self, "nickName", nickName, OBJC_ASSOCIATION_COPY_NONATOMIC);
        
    }
    
    - (NSString *)nickName {
        return objc_getAssociatedObject(self, "nickName");
    }
    
    

    调用

        Person *person = [Person new];
        person.nickName = @"haha";
        NSLog(@"nickName === %@", person.nickName);
    
    

    打印

    image.png

    五,NSUserDefault存储自定义对象

    由于NSUserDefault并不支持存储自定义对象,但是支持存储NSData。
    那我们就先把对象转成NSData再进行存储。

    先在Person类里实现- (instancetype)initWithCoder:(NSCoder *)aDecoder和- (void)encodeWithCoder:(NSCoder *)aCoder两个方法

    //解档
    - (instancetype)initWithCoder:(NSCoder *)aDecoder{
        if (self = [super init]) {
         
            Class c = self.class;
            // 截取类和父类的成员变量
            while (c && c != [NSObject class]) {
                unsigned int count = 0;
                Ivar *ivars = class_copyIvarList(c, &count);
                for (int i = 0; i < count; i++) {
         
                    NSString *key = [NSString stringWithUTF8String:ivar_getName(ivars[i])];
         
                    id value = [aDecoder decodeObjectForKey:key];
         
                    [self setValue:value forKey:key];
                }
                // 获得c的父类
                c = [c superclass];
                free(ivars);
            }
        }
        return self;
    }
     
    //归档
    - (void)encodeWithCoder:(NSCoder *)aCoder{
        Class c = self.class;
        // 截取类和父类的成员变量
        while (c && c != [NSObject class]) {
            unsigned int count = 0;
         
            Ivar *ivars = class_copyIvarList(c, &count);
         
            for (int i = 0; i < count; i++) {
                Ivar ivar = ivars[i];
                NSString *key = [NSString stringWithUTF8String:ivar_getName(ivar)];
         
                id value = [self valueForKey:key];
         
                [aCoder encodeObject:value forKey:key];
            }
            c = [c superclass];
            // 释放内存
            free(ivars);
        }
    }
    

    调用

    - (void)savePersonToUserDefault:(Person *)person {
        NSData *data = [NSKeyedArchiver archivedDataWithRootObject:person];
        if (data) {
            [[NSUserDefaults standardUserDefaults] setObject:data forKey:@"PersonKey"];
            [[NSUserDefaults standardUserDefaults] synchronize];
        }
    }
    
    - (Person *)fetchPerson {
        NSData *data = [[NSUserDefaults standardUserDefaults] objectForKey:@"PersonKey"];
        if (data) {
            Person *person = [NSKeyedUnarchiver unarchiveObjectWithData:data];
            return person;
        }
        return nil;
    }
    

    六,NSCopy,NSMutableCopy

    众所周知,当使用NSCopy和NSMutableCopy时,需要实现<NSCopying, NSMutableCopying>协议,一个一个写起来也是一件麻烦事,使用Runtime可以让这个简单不少。

    - (id)mutableCopyWithZone:(nullable NSZone *)zone {
        id data = [[self.class allocWithZone:zone] init];
        unsigned int count = 0;
        Ivar *ivarList = class_copyIvarList(self.class, &count);
        for (int i = 0; i < count; i ++) {
            Ivar ivar = ivarList[i];
            NSString *name = [NSString stringWithUTF8String:ivar_getName(ivar)];
            id value = [self valueForKey:name];
            [data setValue:value forKey:name];
        }
        return data;
    }
    
    - (id)copyWithZone:(nullable NSZone *)zone {
        id data = [[self.class allocWithZone:zone] init];
        unsigned int count = 0;
        Ivar *ivarList = class_copyIvarList(self.class, &count);
        for (int i = 0; i < count; i ++) {
            Ivar ivar = ivarList[i];
            NSString *name = [NSString stringWithUTF8String:ivar_getName(ivar)];
            id value = [self valueForKey:name];
            [data setValue:value forKey:name];
        }
        return data;
    }
    

    相关文章

      网友评论

        本文标题:iOS探究 --- Runtime的使用场景

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