iOSiOS学习

iOS-Runtime原理及使用

2016-10-24  本文已影响193人  指头飞血

Runtime原理

1.Runtime简称运行时.OC就是运行时机制,(就是系统在运行的时候的一些机制)其中最主要的是消息机制.对于C语言,函数的调用在编译的时候会决定调用哪个函数.对于OC的函数,属于动态调用过程,在编译的时候并不能决定真正调用哪个函数,只有在真正运行的时候才会根据函数的名称找到对应的函数来调用.

2.它是一个主要使用C和汇编写的库,为C添加了面相对象的能力并创造了Objective-C.这就是说它在类信息(Class information)中被加载,完成所有的方法分发,方法转发,等等.Objective-C runtime 创建了所有需要的结构体,让Objective-C 的面相对象编程变为可能.

3.是一套比较底层的纯C语言API,属于1个C语言库, 包含了很多底层的C语言API.在我们平时编写的OC代码中,程序运行过程时,其实最终都是转成了runtime的C语言代码,runtime算是OC的幕后工作者.

4.因为Objc是一门动态语言,所以它总是想办法把一些决定工作从编译连接推迟到运行时.也就是说只有编译器是不够的,还需要一个运行时系统(runtime system)来执行编译后的代码.这就是 Objective-C Runtime 系统存在的意义,它是整个Objc运行框架的一块基石.

5.Mac和iPhone开发者关心的有两个runtime:Modern Runtime(现代的 Runtime)和 Legacy Runtime(过时的Runtime).Modern Runtime:覆盖所有 64 位的 Mac OS X 应用和所有 iPhone OS 的应用.Legacy Runtime:覆盖其他的所有应用(所有32位的 Mac OS X 应用)Method有2种基本类型的方法.Instance Method(实例方法).Class Method(类方法)

Runtime简单使用

Person.h
@interface Person : NSObject
@property(nonatomic,copy)NSString *name;
@property(nonatomic,copy)NSString *gender;
@property(nonatomic,assign)NSInteger age;
-(void)eat;
-(void)play;
@end
Person.m
#import "Person.h"

@implementation Person
-(void)eat{
    NSLog(@"%@吃饭",self.name);
}
-(void)play{
    NSLog(@"%@玩",self.name);
}
@end

先导入头文件

#import "RuntimeViewController.h"
#import "Person+Runtime.h"
#import "Person.h"
#import <objc/message.h>//包含消息机制
#import <objc/runtime.h>//包含对类、成员变量、属性、方法的操作
@interface RuntimeViewController ()
@end
@implementation RuntimeViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    [self setTitle:@"runTime"];//动态添加属性,修改属性值(类别"Person+Runtime.h")
    [self exchangeAttribute];//
//    [self performSelector:@selector(likePlay)];
    objc_msgSend(self,@selector(likePlay));// 动态调用方法(在 LLVM 6.0 中增加了一个 OBJC_OLD_DISPATCH_PROTOTYPES,默认配置在 Apple LLVM 6.0 - Preprocessing 中的 Enable Strict Checking of objc_msgSend Calls 中为Yes 改成NO;)
    [self getAttribute];// 利用runtime遍历一个类的全部成员变量
    [self controlVariables];// 动态控制变量
    [self addMethod];//动态添加方法
    [self exchangeMethod];//动态交换方法实现
}

1.动态为Category扩展加属性

Person+Runtime.h
#import "Person.h"

@interface Person (Runtime)
@property(nonatomic,copy)NSString *height;// 身高
-(void)setHeight:(NSString *)height;
-(NSString *)height;
-(NSString *)addStr1:(NSString *)str1 str2:(NSString *)str2;
@end
Person+Runtime.m
#import "Person+Runtime.h"
#import <objc/message.h>//包含消息机制
#import <objc/runtime.h>//包含对类、成员变量、属性、方法的操作
@implementation Person (Runtime)
static char * heightKey = "heightKey";
-(void)setHeight:(NSString *)height{
     objc_setAssociatedObject(self, heightKey, height, OBJC_ASSOCIATION_COPY_NONATOMIC);
}
-(NSString *)height{
     return objc_getAssociatedObject(self, heightKey);
}
-(NSString *)addStr1:(NSString *)str1 str2:(NSString *)str2{
    
    return [str1 stringByAppendingString:str2];
}
@end
方法实现
-(void)exchangeAttribute{
    Person *p = [[Person alloc]init];
    p.height = @"178";
    NSLog(@"身高==%@",p.height);
}

打印结果

2016-10-24 10:45:09.003 WsBlog[11181:4616582] 身高==178

2.动态控制变量

-(void)controlVariables{
    Person * p = [Person new];
    p.name = @"wym";
    NSLog(@"%@",[p name]);
    unsigned int count;
    //Ivar表示类中的实例变量。Ivar其实就是一个指向objc_ivar结构体指针,它包含了变量名(ivar_name)、变量类型(ivar_type)等信息。
    Ivar *ivar = class_copyIvarList([Person class], &count);
    for (int i = 0; i < count; i ++) {
        Ivar var = ivar[i];
        const char *varName = ivar_getName(var);
        NSString *name = [NSString stringWithCString:varName encoding:NSUTF8StringEncoding];
        if ([name isEqualToString:@"_name"]) {
            object_setIvar(p, var, @"ws");
            break;
        }
    }
    NSLog(@"%@",p.name);
}

打印结果

2016-10-24 10:45:09.004 WsBlog[11181:4616582] wym
2016-10-24 10:45:09.004 WsBlog[11181:4616582] ws

3.利用runtime动态遍历一个类的全部成员变量

-(void)getAttribute{
    //1.导入头文件 <objc/runtime.h>
    unsigned int count = 0;
    //获取指向该类所有属性的指针
    objc_property_t *propeprties = class_copyPropertyList([Person class], &count);
    for (int i = 0; i < count; i++) {
        //获得
        objc_property_t property = propeprties[i];
        //根据objc_property_t 获取所有属性的名称--->C语言的字符串
        const char *name = property_getName(property);
        NSString *attributeName = [NSString stringWithUTF8String:name];
        NSLog(@"%d-----%@",i,attributeName);
    }
}

打印结果

2016-10-24 10:45:09.003 WsBlog[11181:4616582] 0-----height
2016-10-24 10:45:09.003 WsBlog[11181:4616582] 1-----name
2016-10-24 10:45:09.004 WsBlog[11181:4616582] 2-----gender
2016-10-24 10:45:09.004 WsBlog[11181:4616582] 3-----age

4.动态添加方法

void goHome(id self, SEL _cmd){
    NSLog(@"回家");
}
- (void)addMethod
{
    Person *p = [Person new];
    p.name = @"ET";
    
    class_addMethod([Person class], @selector(shise), (IMP)goHome, "v@:");
    
    [p performSelector:@selector(shise) withObject:nil];
}

打印结果

2016-10-24 10:45:09.004 WsBlog[11181:4616582] 回家

5.动态交换方法实现

-(void)exchangeMethod{
    Person *p = [[Person alloc]init];
    p.name = @"ET";
    [p eat];
    [p play];
    // 实现方法交换
    Method m1 = class_getInstanceMethod([Person class], @selector(eat));
    Method m2 = class_getInstanceMethod([Person class], @selector(play));
    method_exchangeImplementations(m1, m2);
    [p eat];
    [p play];
}

打印结果

2016-10-24 10:45:09.004 WsBlog[11181:4616582] ET玩
2016-10-24 10:45:09.005 WsBlog[11181:4616582] ET吃饭
2016-10-24 10:45:09.008 WsBlog[11181:4616582] ET吃饭
2016-10-24 10:45:09.008 WsBlog[11181:4616582] ET玩

6.动态调取方法

-(void)likePlay{
    NSLog(@"喜欢玩");
}

打印结果

2016-10-24 10:45:09.003 WsBlog[11181:4616582] 喜欢玩

http://www.jianshu.com/p/e04e66908b09

上一篇下一篇

猜你喜欢

热点阅读