15-iOS之Runtime常用API以及使用

简介: 15-iOS之Runtime常用API以及使用

Runtime常用API

class相关API

objc_allocateClassPai

创建一个新类和元类

objc_disposeClassPair

销毁一个类及其关联的元类

objc_registerClassPair

注册使用分配的类(注册前添加成员变量)

class_getName

返回类的名称

class_getSuperclass

返回一个类的父类

class_isMetaClass

返回一个布尔值,该值表示类对象是否为元类

class_getInstanceSize

返回类实例的大小

class_addIvar

向类添加新的实例变量

class_copyIvarList

描述类声明的实例变量列表

class_getProperty

返回具有给定类的给定名称的属性

class_copyPropertyList

描述类声明属性列表

class_addMethod

向具有给定名称和实现的类添加新方法

class_getInstanceMethod

返回给定类的指定实例方法

class_getClassMethod

返回一个指向给定类的给定类方法的数据结构的指针

class_copyMethodList

描述类实现的实例方法列表

class_replaceMethod

替换给定类的方法的实现

class_getMethodImplementation

如果将特定消息发送到类的实例,则返回将被调用的函数指针

class_respondsToSelector

返回一个布尔值,该值指示类的实例是否响应特定选择器

class_copyProtocolList

描述类所采用的协议

class_addProperty

向类添加属性

class_getVersion

返回类定义的版本号

class_setVersion

设置类定义的版本号

class_conformsToProtocol

返回一个布尔值,指示一个类是否符合给定的协议

object相关API

object_copy

返回给定对象的副本(ARC不可用)

object_dispose

释放给定对象占用的内存(ARC不可用)

object_setInstanceVariable

更改类实例的实例变量的值(ARC不可用)

object_getInstanceVariable

获取类实例的实例变量的值(ARC不可用)

object_getIvar

读取对象中实例变量的值(不可以访问值类型)

object_setIvar

设置对象中实例变量的值

object_getClassName

返回给定对象的类名

object_getClass

返回对象的类

object_setClass

设置对象的类

获取类定义

objc_getClassList

获取已注册的类定义列表

objc_copyClassList

创建并返回指向所有已注册类定义的指针列表

objc_getClass

返回指定类的类定义

objc_getMetaClass

返回指定类的元类定义

使用实例变量

ivar_getName

返回实例变量的名称

ivar_getTypeEncoding

返回实例变量的类型字符串

关联对象

objc_setAssociatedObject

使用给定的键和关联策略为给定对象设置关联值

objc_getAssociatedObject

返回与给定键的给定对象关联的值

objc_removeAssociatedObjects

删除给定对象的所有关联

发送消息

objc_msgSend

向类的实例发送带有简单返回值的消息

objc_msgSendSuper

向类实例的父类发送带有简单返回值的消息

method相关API

method_invoke

调用指定方法的实现

method_invoke_stret

调用返回数据结构的指定方法的实现

method_getName

返回方法的名称

method_getImplementation

返回方法的实现

method_getTypeEncoding

返回描述方法参数和返回类型的字符串

method_copyReturnType

返回描述方法返回类型的字符串

method_copyArgumentType

返回描述方法的单个参数类型的字符串

method_getReturnType

通过引用返回描述方法返回类型的字符串

method_getNumberOfArguments

返回方法接受的参数数量

method_getArgumentType

通过引用返回描述方法的单个参数类型的字符串

method_getDescription

返回指定方法的方法描述结构

method_setImplementation

设置方法的实现

method_exchangeImplementations

交换两种方法的实现

sel相关API

sel_getName

返回由给定选择器指定的方法的名称

sel_registerName

向运行时系统注册一个方法,将方法名称映射到选择器,并返回选择器值

sel_isEqual

返回一个布尔值,指示两个选择器是否相等

协议相关API

objc_getProtocol

返回指定的协议

objc_copyProtocolList

返回运行时已知的所有协议的数组

objc_allocateProtocol

创建一个新的协议实例

objc_registerProtocol

向运行时注册新创建的协议

protocol_addMethodDescription

向协议添加方法

protocol_addProtocol

将已注册的协议添加到正在构建的另一个协议中

protocol_addProperty

向正在构建的协议添加属性

protocol_getName

返回协议的名称

protocol_isEqual

返回一个布尔值,指示两个协议是否相等

protocol_copyPropertyList

返回由协议声明的属性数组

protocol_getProperty

返回给定协议的指定属性

protocol_copyProtocolList

返回协议采用的协议数组

protocol_conformsToProtocol

返回一个布尔值,指示一个协议是否符合另一个协议

属性相关

property_getName

返回属性的名称

property_getAttributes

返回属性的属性字符串

property_copyAttributeValue

返回给定属性名称的属性属性的值

property_copyAttributeList

返回给定属性的属性属性数组


常用API的使用示例

  • 动态创建类并添加成员变量和方法

void test1(void) {
    Class personCls = objc_allocateClassPair([NSObject class], "Person", 0);//创建类
    class_addIvar(personCls, "name", sizeof(NSString *), 0, "@"); //添加成员变量
    IMP runImp = imp_implementationWithBlock(^(id p1, id p2){
        NSLog(@"run - %@ - %@", p1, p2);// run - <Person: 0x100621420> - lisi
    });//添加方法实现
    class_addMethod(personCls, sel_registerName("run:"), runImp, nil); //添加方法
    objc_registerClassPair(personCls); //注册类
    id person = [personCls new]; //初始化类
    [person setValue:@"zs" forKey:@"name"]; //给成员变量赋值
    objc_msgSend(person, sel_registerName("run:"), @"lisi"); //调用run:方法
    NSLog(@"%@", [person valueForKey:@"name"]); //打印结果: zs
    NSLog(@"%@", object_getClass(person));//打印结果: Person
}
• 类中的成员变量的常用操作
@interface Student : NSObject
@property(strong, nonatomic) NSString *hobby;
@property(assign, nonatomic) NSInteger age;
@end
@implementation Student
@end
void test2(void) {
    //获取实例变量的值
    Student *stu = [Student new];
    stu.hobby = @"hobby - value";
    Ivar ivar = class_getInstanceVariable([stu class], "_hobby"); //获取ivar
    id name = object_getIvar(stu, ivar); //获取成员变量的值
    NSLog(@"%@", name); //打印结果: hobby - value
    object_setIvar(stu, ivar, @"set - value"); //给成员变量赋值
    id name2 = object_getIvar(stu, ivar); //获取成员变量的值
    NSLog(@"%@", name2); //打印结果: set - value
    unsigned int count = 0;
    Ivar *ivars = class_copyIvarList([stu class], &count); //获取ivar list
    for (int i = 0; i < count; i++) {
        Ivar var = ivars[i];
        const char *name = ivar_getName(var); //取出成员变量的名称
        NSLog(@"所有成员变量: %@", [NSString stringWithCString:name encoding:NSUTF8StringEncoding]);
    }//打印结果:所有成员变量: _hobby;所有成员变量: _age
}
  • 整合上面两段代码
    将person的isa指向了Student,以后访问person的时候,相当于直接访问student

void test3(void) {
    object_setClass(person, [stu class]);
    NSLog(@"%@", [person valueForKey:@"_hobby"]); //打印结果: zs
}
  • 实例方法的方法交换

@interface Student : NSObject
- (void)studentTest;
@end
@implementation Student
- (void)studentTest {
    NSLog(@"studentTest");
}
@end
@interface Student (Cate)
@end
@implementation Student (Cate)
+ (void)load {
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{ //hook实例方法传入类对象
        [self hookMethod:[self class] originSelector:@selector(studentTest) swizzledSelector:@selector(hook_studentTest)];
    });
}
+ (void)hookMethod:(Class)cls originSelector:(SEL)originalSelector swizzledSelector:(SEL)swizzledSelector {
    Method originalMethod = class_getInstanceMethod(cls, originalSelector);//获取当前类的Method
    Method swizzledMethod = class_getInstanceMethod(cls, swizzledSelector);//获取当前类的hook Method
    //向当前类中增加方法,并将实现指向当前类中的原始方法,防止调用[self hook_xxx]的时候找不到方法
    //意味着调用当前类中的hook_xxx方法的时候,相当于调用当前类的原始方法
    //添加不存在的方法此处返回YES
    BOOL didAddMethod = class_addMethod(cls, originalSelector, method_getImplementation(swizzledMethod), method_getTypeEncoding(swizzledMethod));
    if (didAddMethod) {
        //意味着调用当前中的原始方法的时候,相当于调用当前类的hook_xxx方法
        class_replaceMethod(cls, swizzledSelector, method_getImplementation(originalMethod), method_getTypeEncoding(originalMethod));
    } else {//交换imp方法实现
        method_exchangeImplementations(originalMethod, swizzledMethod);
    }
}
- (void)hook_studentTest {
    NSLog(@"hook - studentTest");
    [self hook_studentTest];
}
@end
void test4(void) {
    Student *stu = [Student new];
    [stu studentTest];
}
int main(int argc, const char * argv[]) {
    @autoreleasepool {
        test4();
    }
    return 0;
}

打印结果:

hook - studentTest
studentTest

调用studentTest前先调用了hook - studentTest

  • 类方法的方法交换

@interface Student : NSObject
+ (void)classMethod;
@end
@implementation Student
+ (void)classMethod {
    NSLog(@"classMethod");
}
@end
@interface Student (Cate)
@end
@implementation Student (Cate)
+ (void)load {
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        //object_getClass([self class]) - 改动
        //实例方法向类对象里面查找,类方法向元类方法里面查找,故此处应该传入元类对象
        [self hookMethod:object_getClass([self class]) originSelector:@selector(classMethod) swizzledSelector:@selector(hook_classMethod)];
    });
}
+ (void)hookMethod:(Class)cls originSelector:(SEL)originalSelector swizzledSelector:(SEL)swizzledSelector {
    Method originalMethod = class_getClassMethod(cls, originalSelector);//获取当前类的Method - 改动
    Method swizzledMethod = class_getClassMethod(cls, swizzledSelector);//获取当前类的hook Method - 改动
    //向当前类中增加方法,并将实现指向当前类中的原始方法,防止调用[self hook_xxx]的时候找不到方法
    //意味着调用当前类中的hook_xxx方法的时候,相当于调用当前类的原始方法
    //添加不存在的方法此处返回YES
    BOOL didAddMethod = class_addMethod(cls, originalSelector, method_getImplementation(swizzledMethod), method_getTypeEncoding(swizzledMethod));
    if (didAddMethod) {
        //意味着调用当前中的原始方法的时候,相当于调用当前类的hook_xxx方法
        class_replaceMethod(cls, swizzledSelector, method_getImplementation(originalMethod), method_getTypeEncoding(originalMethod));
    } else {//交换imp方法实现
        method_exchangeImplementations(originalMethod, swizzledMethod);
    }
}
+ (void)hook_classMethod {
    NSLog(@"hook_classMethod");
    [self hook_classMethod];
}
@end
void test6(void) {
    [Student classMethod];
}
int main(int argc, const char * argv[]) {
    @autoreleasepool {
        test6();
    }
    return 0;
}

打印结果:

hook_classMethod
classMethod
  • 代理方法的方法交换

@protocol MyDelegate <NSObject>
- (void)delegateMethod;
@end
@interface Student : NSObject
@property(weak, nonatomic) id <MyDelegate> delegate;
- (void)callMethod;
@end
@implementation Student
- (void)callMethod {
    if ([self.delegate respondsToSelector:@selector(delegateMethod)]) {
        [self.delegate delegateMethod];
    }
}
@end
@interface Student (Cate)
@end
@implementation Student (Cate)
+ (void)load {
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        [self hookMethod:[self class] originSelector:@selector(setDelegate:) swizzledSelector:@selector(hook_setDelegate:)];
    });
}
+ (void)hookMethod:(Class)cls originSelector:(SEL)originalSelector swizzledSelector:(SEL)swizzledSelector {
    Method originalMethod = class_getInstanceMethod(cls, originalSelector);//获取当前类的Method
    Method swizzledMethod = class_getInstanceMethod(cls, swizzledSelector);//获取当前类的hook Method
    //向当前类中增加方法,并将实现指向当前类中的原始方法,防止调用[self hook_xxx]的时候找不到方法
    //意味着调用当前类中的hook_xxx方法的时候,相当于调用当前类的原始方法
    //添加不存在的方法此处返回YES
    BOOL didAddMethod = class_addMethod(cls, originalSelector, method_getImplementation(swizzledMethod), method_getTypeEncoding(swizzledMethod));
    if (didAddMethod) {
        //意味着调用当前中的原始方法的时候,相当于调用当前类的hook_xxx方法
        class_replaceMethod(cls, swizzledSelector, method_getImplementation(originalMethod), method_getTypeEncoding(originalMethod));
    } else {//交换imp方法实现
        method_exchangeImplementations(originalMethod, swizzledMethod);
    }
}
- (void)hookMethod:(Class)cls originSelector:(SEL)originalSelector swizzledSelector:(SEL)swizzledSelector {
    Method originalMethod = class_getInstanceMethod(cls, originalSelector);//获取代理类的Method
    Method swizzledMethod = class_getInstanceMethod([self class], swizzledSelector);//获取当前类的hook Method
    //向代理类中增加方法,并将实现指向代理类中的原始方法,防止调用[self hook_xxx]的时候找不到方法
    //意味着调用代理类中的hook_xxx方法的时候,相当于调用代理类的原始方法
    //添加不存在的方法此处返回YES
    BOOL didAddMethod = class_addMethod(cls, swizzledSelector, class_getMethodImplementation(cls, originalSelector), method_getTypeEncoding(originalMethod));
    if (didAddMethod) {//替换代理类中的原始方法的实现为当前类中的hook_xxx方法
        //意味着调用代理中的原始方法的时候,相当于调用当前类的hook_xxx方法
        class_replaceMethod(cls, originalSelector, class_getMethodImplementation([self class], swizzledSelector), method_getTypeEncoding(swizzledMethod));
    }else {
        NSLog(@"来到此处说明交换的方法已经在原类中实现了,需要更换一下hook的方法名称");
    }
}
- (void)hook_setDelegate:(id<MyDelegate>)delegate {
    [self hookMethod:[delegate class] originSelector:@selector(delegateMethod) swizzledSelector:@selector(hook_delegateMethod)];
    [self hook_setDelegate:delegate];
}
- (void)hook_delegateMethod {
    NSLog(@"hook_delegateMethod");
    [self hook_delegateMethod];
}
@end
@interface MyClass : NSObject<MyDelegate>
@end
@implementation MyClass
- (void)delegateMethod {
    NSLog(@"MyClass - delegateMethod");
}
@end
void test5(void) {
    Student *stu = [Student new];
    MyClass *myClass = [MyClass new];
    stu.delegate = myClass;
    [stu callMethod];
}
int main(int argc, const char * argv[]) {
    @autoreleasepool {
        test5();
    }
    return 0;
}

打印结果:

hook_delegateMethod
MyClass - delegateMethod

本文部分内容来可能来源于网络,发布的内容如果侵犯了您的权益,请联系我们尽快删除!

相关文章
|
10月前
|
API iOS开发
iOS面试关于runtime
iOS面试关于runtime
81 0
|
文字识别 API iOS开发
iOS小技能:iOS13 证件扫描 & 文字识别API
1. 应用场景:证件扫描、文字识别 2. 原理:利用iOS13 VNDocumentCameraViewController的证件扫描和VNRecognizeTextRequest文字识别功能进行实现
325 0
iOS小技能:iOS13 证件扫描 & 文字识别API
|
20天前
|
机器学习/深度学习 API iOS开发
探索iOS开发中的SwiftUI框架深入理解RESTful API设计原则与最佳实践
【7月更文挑战第30天】本文深入探讨了SwiftUI框架在iOS开发中的应用,分析了其对用户界面构建的简化方法及性能优化。通过比较传统UI构建方式与SwiftUI的差异,揭示了SwiftUI如何提高开发效率和用户体验。文章还讨论了SwiftUI在实际项目中的集成策略,并展望了其未来的发展方向。 【7月更文挑战第30天】在数字时代的浪潮中,RESTful API如同一座桥梁,连接着不同的软件系统。本文将探讨RESTful API的核心设计原则,揭示其背后的哲学思想,并通过实例分析展示如何将这些原则应用于实际开发中。我们将从资源定位、接口一致性到HTTP方法的恰当使用,逐一剖析,旨在为开发者提供
38 1
|
3月前
|
缓存 JSON API
IOS网络编程:什么是 RESTful API?如何使用 RESTful 风格设计 API?
IOS网络编程:什么是 RESTful API?如何使用 RESTful 风格设计 API?
85 3
|
小程序 API Android开发
小程序获取WIFI的API(IOS conncetWifi()自动跳转设置页)
小程序获取WIFI的API(IOS conncetWifi()自动跳转设置页)
347 0
|
编译器 iOS开发
iOS Runtime详细介绍及实战使用(二)
iOS Runtime详细介绍及实战使用
 iOS Runtime详细介绍及实战使用(二)
|
API iOS开发
iOS Runtime详细介绍及实战使用(一)
iOS Runtime详细介绍及实战使用
|
iOS开发
iOS开发- runtime基本用法解析和用runtime给键盘添加工具栏和按钮响应事件
iOS开发- runtime基本用法解析和用runtime给键盘添加工具栏和按钮响应事件
128 0
|
JSON 前端开发 JavaScript
iOS Principle:Runtime(下)
iOS Principle:Runtime(下)
84 0
iOS Principle:Runtime(下)
|
缓存 编译器 Swift
iOS Principle:Runtime(中)
iOS Principle:Runtime(中)
159 0
iOS Principle:Runtime(中)