zoukankan      html  css  js  c++  java
  • IOS Runtime的用法

     什么是runtime?


    1> runtime是一套底层的C语言API(包含很多强大实用的C语言数据类型、C语言函数)
    2> 实际上,平时我们编写的OC代码,底层都是基于runtime实现的
    * 也就是说,平时我们编写的OC代码,最终都是转成了底层的runtime代码(C语言代码)


    runtime有啥用?


    1> 能动态产生一个类、一个成员变量、一个方法
    2> 能动态修改一个类、一个成员变量、一个方法
    3> 能动态删除一个类、一个成员变量、一个方法


    常见的函数、头文件


    #import <objc/runtime.h> :           成员变量、类、方法
    Ivar * class_copyIvarList :              获得某个类内部的所有成员变量
    Method * class_copyMethodList :     获得某个类内部的所有方法
    Method class_getInstanceMethod :   获得某个实例方法(对象方法,减号-开头)
    Method class_getClassMethod :        获得某个类方法(加号+开头)
    method_exchangeImplementations : 交换2个方法的具体实现

    #import <objc/message.h> : 消息机制
    objc_msgSend(....)

    #import "HMViewController.h"
    #import "HMPerson.h"
    #import <objc/runtime.h>
    #import <objc/message.h>
    
    @interface HMViewController ()
    @property (weak, nonatomic) IBOutlet UIImageView *iconView1;
    @property (weak, nonatomic) IBOutlet UIImageView *iconView2;
    
    @property (nonatomic, strong) NSMutableArray *names;
    @property (nonatomic, strong) NSArray *books;
    
    @end
    
    @implementation HMViewController
    
    - (NSMutableArray *)names
    {
        if (_names == nil) {
            self.names = [NSMutableArray array];
        }
        return _names;
    }
    
    - (void)viewDidLoad
    {
        [super viewDidLoad];
        
    //    NSDictionary *info = @{@"name" : @"jack", @"age" : @10};
    //    
    //    NSString *key = nil;
    //    
    //    NSLog(@"%@", info[key]);
        
        NSMutableDictionary *info = [NSMutableDictionary dictionary];
        info[@"name"] = nil;
        
    //    self.books = @[@"kiuhua", @"xxx"];
    //
    //    NSLog(@"%@", self.books[4]);
        
    //    [self addName:@"jack"];
    //    [self addName:@"rose"];
    //    [self addName:@"jim"];
    //
    //    NSLog(@"%@", self.names[4]);
    //    NSLog(@"%@", [self.names objectAtIndex:4]);
    }
    
    - (void)addName:(NSString *)name
    {
        [self.names addObject:name];
    }
    
    - (void)imageSwizzle
    {
        // 什么是iOS Swizzle?利用运行时函数交换2个方法的实现
        
        //    BOOL iOS7 = [[UIDevice currentDevice].systemVersion floatValue] >= 7.0;
        //    if (iOS7) {
        //        self.iconView1.image = [UIImage imageNamed:@"face_os7"];
        //        self.iconView2.image = [UIImage imageNamed:@"vip_os7"];
        //    } else {
        //        self.iconView1.image = [UIImage imageNamed:@"face"];
        //        self.iconView2.image = [UIImage imageNamed:@"vip"];
        //    }
        self.iconView1.image = [UIImage imageNamed:@"face"];
        self.iconView2.image = [UIImage imageNamed:@"vip"];
    }
    
    - (void)testRuntimeIvar
    {
        // Ivar : 成员变量
        unsigned int count = 0;
        // 获得所有的成员变量
        Ivar *ivars = class_copyIvarList([HMPerson class], &count);
        for (int i = 0; i<count; i++) {
            // 取得i位置的成员变量
            Ivar ivar = ivars[i];
            const char *name = ivar_getName(ivar);
            const char *type = ivar_getTypeEncoding(ivar);
            NSLog(@"%d %s %s", i, name, type);
        }
        
        //    HMPerson *p = [[HMPerson alloc] init];
        //    objc_msgSend(p, @selector(setAge:), 20);
        
        //    NSLog(@"%d", p.age);
    }

    HMPerson.h /.m(获取所有成员变量)

    #import <Foundation/Foundation.h>
    
    @interface HMPerson : NSObject <NSCoding>
    @property (nonatomic, assign) int age;
    @property (nonatomic, copy) NSString *name;
    @property (nonatomic, assign) double height;
    - (void)run;
    @end
    View Code
    #import "HMPerson.h"
    #import <objc/runtime.h>
    
    @implementation HMPerson
    - (void)run
    {
        NSLog(@"run----");
    }
    
    - (void)encodeWithCoder:(NSCoder *)encoder
    {
        unsigned int count = 0;
        Ivar *ivars = class_copyIvarList([HMPerson class], &count);
        for (int i = 0; i<count; i++) {
            // 取得i位置的成员变量
            Ivar ivar = ivars[i];
            const char *name = ivar_getName(ivar);
            NSString *key = [NSString stringWithUTF8String:name];
            [encoder encodeObject:[self valueForKeyPath:key] forKey:key];
        }
    }
    
    @end
    View Code

     UIImage+Extension(交换2个方法的实现)

    #import <objc/runtime.h>
    
    @implementation UIImage (Extension)
    /**
     *  只要分类被装载到内存中,就会调用1次
     */
    + (void)load
    {
        Method otherMehtod = class_getClassMethod(self, @selector(imageWithName:));
        Method originMehtod = class_getClassMethod(self, @selector(imageNamed:));
        // 交换2个方法的实现
        method_exchangeImplementations(otherMehtod, originMehtod);
    }
    
    + (UIImage *)imageWithName:(NSString *)name
    {
        BOOL iOS7 = [[UIDevice currentDevice].systemVersion floatValue] >= 7.0;
        UIImage *image = nil;
        if (iOS7) {
            NSString *newName = [name stringByAppendingString:@"_os7"];
            image = [UIImage imageWithName:newName];
        }
        
        if (image == nil) {
            image = [UIImage imageWithName:name];
        }
        return image;
    }
    
    
    @end
    View Code

    NSObject+Extension(交换2个方法的实现)

    #import <objc/runtime.h>
    
    @implementation NSObject(Extension)
    + (void)swizzleClassMethod:(Class)class originSelector:(SEL)originSelector otherSelector:(SEL)otherSelector
    {
        Method otherMehtod = class_getClassMethod(class, otherSelector);
        Method originMehtod = class_getClassMethod(class, originSelector);
        // 交换2个方法的实现
        method_exchangeImplementations(otherMehtod, originMehtod);
    }
    
    + (void)swizzleInstanceMethod:(Class)class originSelector:(SEL)originSelector otherSelector:(SEL)otherSelector
    {
        Method otherMehtod = class_getInstanceMethod(class, otherSelector);
        Method originMehtod = class_getInstanceMethod(class, originSelector);
        // 交换2个方法的实现
        method_exchangeImplementations(otherMehtod, originMehtod);
    }
    @end
    
    @implementation NSArray(Extension)
    + (void)load
    {
        [self swizzleInstanceMethod:NSClassFromString(@"__NSArrayI") originSelector:@selector(objectAtIndex:) otherSelector:@selector(hm_objectAtIndex:)];
    }
    
    - (id)hm_objectAtIndex:(NSUInteger)index
    {
        if (index < self.count) {
            return [self hm_objectAtIndex:index];
        } else {
            return nil;
        }
    }
    
    @end
    
    @implementation NSMutableArray(Extension)
    + (void)load
    {
        [self swizzleInstanceMethod:NSClassFromString(@"__NSArrayM") originSelector:@selector(addObject:) otherSelector:@selector(hm_addObject:)];
        [self swizzleInstanceMethod:NSClassFromString(@"__NSArrayM") originSelector:@selector(objectAtIndex:) otherSelector:@selector(hm_objectAtIndex:)];
    }
    
    - (void)hm_addObject:(id)object
    {
        if (object != nil) {
            [self hm_addObject:object];
        }
    }
    
    - (id)hm_objectAtIndex:(NSUInteger)index
    {
        if (index < self.count) {
            return [self hm_objectAtIndex:index];
        } else {
            return nil;
        }
    }
    @end
    View Code

     

  • 相关阅读:
    2020年. NET Core面试题
    java Context namespace element 'component-scan' and its parser class ComponentScanBeanDefinitionParser are only available on JDK 1.5 and higher 解决方法
    vue 淡入淡出组件
    java http的get、post、post json参数的方法
    vue 父子组件通讯案例
    Vue 生产环境解决跨域问题
    npm run ERR! code ELIFECYCLE
    Android Studio 生成apk 出现 :error_prone_annotations.jar (com.google.errorprone:error) 错误
    记忆解析者芜青【总集】
    LwIP应用开发笔记之十:LwIP带操作系统基本移植
  • 原文地址:https://www.cnblogs.com/liuwj/p/6752679.html
Copyright © 2011-2022 走看看