本文介绍: 1.Objective-C中的Runtimea) Objective-C是一门动态比较强的编程语言,跟C、C++等语言有着很大的不同 1) C、C++都是 编写代码–>编译连接–>运行 2) 而OC则可以运行时候动态的去修改例如动态的去调用自身类或者其他类的方法,或者增加、交换方法实现b) Objective-C的动态性是由Runtime API来支撑的c) Runtime API提供的接口基本都是C语言的,源码由CC++汇编语言编写.
a) Objective-C是一门动态性比较强的编程语言,跟C、C++等语言有着很大的不同
    1) C、C++都是 编写代码-->编译连接-->运行
    
    2) 而OC则可以在运行的时候动态的去修改例如动态的去调用自身类或者其他类的方法,或者增加、交换方法实现

b) Objective-C的动态性是由Runtime API来支撑的

c) Runtime API提供的接口基本都是C语言的,源码由CC++汇编语言编写
a) &(按位)如果大家都是1结果才是1,其他都是0,用来取出设置特定的位

b) |(按位)只要有一个1结果就是1,其他都是,用来取出或设置特定的位

c) ~(运算取反)
#import <Foundation/Foundation.h&gt;
@interface MJPerson : NSObject
//@property (assign, nonatomic, getter=isTall) BOOL tall;
//@property (assign, nonatomic, getter=isRich) BOOL rich;
//@property (assign, nonatomic, getter=isHansome) BOOL handsome;

- (void)setTall:(BOOL)tall;
- (void)setRich:(BOOL)rich;
- (void)setHandsome:(BOOL)handsome;

- (BOOL)isTall;
- (BOOL)isRich;
- (BOOL)isHandsome;
@end

#import "MJPerson.h"
// &amp;可以用来取出特定的位
// 0000 0111
//&amp;0000 0100
//------
// 0000 0100

// 掩码,一般用来按位与(&amp;)运算
// 宏的替换就是字符串替换所以要注意运算先后次序
//#define MJTallMask 1
//#define MJRichMask 2
//#define MJHandsomeMask 4

//#define MJTallMask 0b00000001
//#define MJRichMask 0b00000010
//#define MJHandsomeMask 0b00000100

#define MJTallMask (1<<0)
#define MJRichMask (1<<1)
#define MJHandsomeMask (1<<2)

@interface MJPerson()
{
    char _tallRichHansome;
}
@end

@implementation MJPerson

// 0010 1010
//&amp;1111 1101
//----------
// 0010 1000

- (instancetype)init
{
    if (self = [super init]) {
        _tallRichHansome = 0b00000100;
    }
    return self;
}

- (void)setTall:(BOOL)tall
{
    if (tall) {
        _tallRichHansome |= MJTallMask;
    } else {
        _tallRichHansome &amp;= ~MJTallMask;
    }
}

- (BOOL)isTall
{
    // 只占1位 返回的也是1位 然而boll类型一个字节所以会强制变成8位(全部用你当前结果覆盖其余的位)那么解决办法 !!(2个感叹号) 或者 定义结构体的时候占2位
    // 结果用BOLL强制转 或者 !!(2个感叹号)
    return !!(_tallRichHansome &amp; MJTallMask);
}

- (void)setRich:(BOOL)rich
{
    if (rich) {
        _tallRichHansome |= MJRichMask;
    } else {
        _tallRichHansome &amp;= ~MJRichMask;
    }
}

- (BOOL)isRich
{
    return !!(_tallRichHansome &amp; MJRichMask);
}

- (void)setHandsome:(BOOL)handsome
{
    if (handsome) {
        _tallRichHansome |= MJHandsomeMask;
    } else {
        _tallRichHansome &amp;= ~MJHandsomeMask;
    }
}

- (BOOL)isHandsome
{
    return !!(_tallRichHansome &amp; MJHandsomeMask);
}
@end
d)结构体的方式实现
e) 结构体是支持位域 字节排布 从低到高 从右到左
f)运算的效率比直接取值效率高
#import "MJPerson.h"
//#define MJTallMask (1<<0)
//#define MJRichMask (1<<1)
//#define MJHandsomeMask (1<<2)
@interface MJPerson()
{
    // 位域
    // 结构体是支持位域 字节排布 从低到高 从右到左
    struct {
        char tall : 1;
        char rich : 1;
        char handsome : 1;
    } _tallRichHandsome;
}
@end

@implementation MJPerson

- (void)setTall:(BOOL)tall
{
    _tallRichHandsome.tall = tall;
}

- (BOOL)isTall
{
    return !!_tallRichHandsome.tall;
}

- (void)setRich:(BOOL)rich
{
    _tallRichHandsome.rich = rich;
}

- (BOOL)isRich
{
    return !!_tallRichHandsome.rich;
}

- (void)setHandsome:(BOOL)handsome
{
    _tallRichHandsome.handsome = handsome;
}

- (BOOL)isHandsome
{
    return !!_tallRichHandsome.handsome;
}
@end
g) 用共用体的方式实现
    1) 共用体:大家共用一块内存
    2) 结构:结构体内的成员都是单独存在,占不同的内存
#import "MJPerson.h"
#define MJTallMask (1<<0)
#define MJRichMask (1<<1)
#define MJHandsomeMask (1<<2)
#define MJThinMask (1<<3)
@interface MJPerson()
{
    union {
        int bits;
        
        struct {
            char tall : 4;
            char rich : 4;
            char handsome : 4;
            char thin : 4;
        };
    } _tallRichHandsome;
}
@end

@implementation MJPerson

- (void)setTall:(BOOL)tall
{
    if (tall) {
        _tallRichHandsome.bits |= MJTallMask;
    } else {
        _tallRichHandsome.bits &amp;= ~MJTallMask;
    }
}

- (BOOL)isTall
{
    return !!(_tallRichHandsome.bits &amp; MJTallMask);
}

- (void)setRich:(BOOL)rich
{
    if (rich) {
        _tallRichHandsome.bits |= MJRichMask;
    } else {
        _tallRichHandsome.bits &amp;= ~MJRichMask;
    }
}

- (BOOL)isRich
{
    return !!(_tallRichHandsome.bits & MJRichMask);
}

- (void)setHandsome:(BOOL)handsome
{
    if (handsome) {
        _tallRichHandsome.bits |= MJHandsomeMask;
    } else {
        _tallRichHandsome.bits &= ~MJHandsomeMask;
    }
}

- (BOOL)isHandsome
{
    return !!(_tallRichHandsome.bits & MJHandsomeMask);
}

- (void)setThin:(BOOL)thin
{
    if (thin) {
        _tallRichHandsome.bits |= MJThinMask;
    } else {
        _tallRichHandsome.bits &= ~MJThinMask;
    }
}

- (BOOL)isThin
{
    return !!(_tallRichHandsome.bits & MJThinMask);
}
@end
h) 例如kvo或者autoresizingMask是怎么知道传入的不同按位或的值呢?
    1) 最终传入的值与自身进行按位与如果成立则包含了自身;
a) 要想学习Runtime,首先要了解它底层的一些常用数据结构比如isa指针

b)arm64架构之前,isa就是一个普通的指针存储着Class、Meta-Class对象的内存地址

c)arm64架构开始,对isa进行了优化,变成了一个共用体(union结构,还使用位域来存储更多的信息

d) 64位之前isa就是Class类型,是isa_t类型

e) isa详解-位域

  • 4.Class的结构
a)对象/元类对象地址最后三位都是0,因为isa底层原理

b) 一开始是只有class_ro_t,然后创建class_rw_t并且拷贝class_ro_t的内容,并且将bits指向class_rw_t

c) class_rw_t里面methodspropertiesprotocols是二维数组,是可读可写的,包含了类的初始内容、分类的内容 

d) class_ro_t里面baseMethodList、baseProtocols、ivars、baseProperties是一维数组,是只读的,包含了类的初始内容

e) method_t是对方法/函数封装

f) Type Encoding

g) cache(方法缓存)
    1) Class内部结构中有个方法缓存cache_t),用散列表哈希表)来缓存曾经调用过的方法,可以提高方法的查找速度
    2) 方法缓存cache调用过的方法直接扔到缓存里面,下次再调用直接从cache调用
    3) 缓存源码实现查找
        3.1) objc-cache.mm
        3.2) bucket_t * cache_t::find(cache_key_t k, id receiver)

h)列表
    1) 存的时候通过一个位运算去存,前面没有的就会设置为NULL(牺牲内存空间来换取执行效率/空间时间)
    2) 散列表扩容的时候是在原来容量基础上X2,并且清空原来缓存数据,重新开始缓存
    3) 存或者取的时候有可能是一样的 那么做法是-1或者+1,重新生成index

a) OC中的方法调用,其实都是转换objc_msgSend函数调用

b) objc_msgSend执行流程可以分为3阶段
    1) 消息发送
    2) 动态方法解析
    3) 消息转发
    
c) 源码跟读

d) 消息发送
    1) 查找方式
        1.1) 二分查找(排好序的 从中间开始分然后查找)
        1.2) 线性查找(普通的for循环遍历查找)

e) 动态方法解析
    1) 开发者可以实现以下方法,来动态添加方法实现
        1.1) +resolveInstanceMethod:// 对象方法
        1.2)
+resolveClassMethod:// 类方法
    2) 动态解析过后,会重新走“消息发送”的流程
        2.1) “从receiverClass的cache中查找方法”这一步开始执行

f) 消息转发
    1) 这个步骤你就开始找不到源码2)自己的类没有能力处理这个方法
    3) 元类对象:是一种特殊的类对象,类对象的类对象
    4) 类方法也是有消息转发机制5) 开发者可以在forwardInvocation:方法中自定义任何逻辑

    6) 生成NSMethodSignature方式

a) @dynamic (告诉编译器不要自动生成setter&getter方法的实现、不要自动生成成员变量)

b) @synthesize (自动生成setter&getter方法的实现和自动生成成员变量)

c) super调用底层转换objc_msgSendSuper2函数的调用,接收2参数
    1) struct objc_super2

        1.1) receiver是消息接收者
        1.2) current_class是receiver的Class对象-->superclass父类对象
    2) SEL
  • 7.LLVM的中间代码(IR)
a) Objective-C在变为机器代码之前,会被LLVM编译器转换为中间代码(Intermediate Representation1) OC --> 中间代码(.ll文件) --> 汇编、机器代码
    
b) 可以使用以下命令行指令生成中间代码
    1) clang -emit-llvm -S main.m
    
c) 语法简介
    1) @ - 全局变量
    2) % - 局部变量
    3) alloca -当前执行的函数的堆栈帧中分配内存,当该函数返回到其调用者时,将自动释放内存
    4) i32 - 324字节整数
    5) align - 对齐
    6) load - 读出
    7) store 写入
    8) icmp - 两个数值比较返回布尔值
    9) br - 选择分支,根据条件来转向label,不根据条件跳转的话类似 goto
    10) label - 代码标签
    11) call - 调用函数

d) 官方文档1) https://llvm.org/docs/LangRef.html
a) 查看私有成员变量
    1) 设置UITextField占位文字颜色

b) 字典模型
    1) 利用Runtime遍历所有的属性或者成员变量
    2) 利用KVC设值

c) 替换方法实现
    1) class_replaceMethod
    2) method_exchangeImplementations

a)1) 动态创建一个类(参数父类类名额外内存空间1.1) Class objc_allocateClassPair(Class superclass, const char *name, size_t extraBytes)

    2) 注册一个类(要在类注册之前添加成员变量2.1) void objc_registerClassPair(Class cls) 

    3) 销毁一个类
        3.1) void objc_disposeClassPair(Class cls)

    4) 获取isa指向的Class
        4.1) Class object_getClass(id obj)

    5) 设置isa指向的Class
        5.1) Class object_setClass(id obj, Class cls)

    6) 判断一个OC对象是否为Class
        6.1) BOOL object_isClass(id obj)

    7) 判断一个Class是否元类
        7.1) BOOL class_isMetaClass(Class cls)

    8) 获取父类
        8.1) Class class_getSuperclass(Class cls)

b) 成员变量
    1) 获取一个实例变量信息
        1.1) Ivar class_getInstanceVariable(Class cls, const char *name)

    2) 拷贝实例变量列表(最后需要调用free释放)
        2.1) Ivar *class_copyIvarList(Class cls, unsigned int *outCount)

    3) 设置和获取成员变量的值
        3.1) void object_setIvar(id obj, Ivar ivar, id value)
        3.2) id object_getIvar(id obj, Ivar ivar)

    4) 动态添加成员变量(已经注册的类是不能动态添加成员变量的)
        4.1) BOOL class_addIvar(Class cls, const char * name, size_t size, uint8_t alignment, const char * types)

    5) 获取成员变量的相关信息
        5.1) const char *ivar_getName(Ivar v)
        5.2) const char *ivar_getTypeEncoding(Ivar v)

c) 属性
    1) 获取一个属性
        1.1) objc_property_t class_getProperty(Class cls, const char *name)

    2) 拷贝属性列表(最后需要调用free释放)
        2.1) objc_property_t *class_copyPropertyList(Class cls, unsigned int *outCount)

    3) 动态添加属性
        3.1) BOOL class_addProperty(Class cls, const char *name, const objc_property_attribute_t *attributes,
                  unsigned int attributeCount)

    4) 动态替换属性
        4.1) void class_replaceProperty(Class cls, const char *name, const objc_property_attribute_t *attributes,
                      unsigned int attributeCount)

    5) 获取属性的一些信息
        5.1) const char *property_getName(objc_property_t property)
        5.2) const char *property_getAttributes(objc_property_t property)

d) 方法
    1) 获得一个实例方法、类方法
        1.1) Method class_getInstanceMethod(Class cls, SEL name)
        1.2) Method class_getClassMethod(Class cls, SEL name)

    2) 方法实现相关操作
        2.1) IMP class_getMethodImplementation(Class cls, SEL name) 
        2.2) IMP method_setImplementation(Method m, IMP imp)
        2.3) void method_exchangeImplementations(Method m1, Method m2) 

    3) 拷贝方法列表(最后需要调用free释放)
        3.1) Method *class_copyMethodList(Class cls, unsigned int *outCount)

    4) 动态添加方法
        4.1) BOOL class_addMethod(Class cls, SEL name, IMP imp, const char *types)

    5) 动态替换方法
        5.1) IMP class_replaceMethod(Class cls, SEL name, IMP imp, const char *types)

    6) 获取方法的相关信息(带有copy需要调用free去释放)
        6.1) SEL method_getName(Method m)
        6.2) IMP method_getImplementation(Method m)
        6.3) const char *method_getTypeEncoding(Method m)
        6.4) unsigned int method_getNumberOfArguments(Method m)
        6.5) char *method_copyReturnType(Method m)
        6.6) char *method_copyArgumentType(Method m, unsigned int index)

    7) 选择器相关
        7.1) const char *sel_getName(SEL sel)
        7.2) SEL sel_registerName(const char *str)

    8)block作为方法实现
        8.1) IMP imp_implementationWithBlock(id block)
        8.2) id imp_getBlock(IMP anImp)
        8.3) BOOL imp_removeBlock(IMP anImp)
a) objc_msgSendSuper 和 objc_msgSendSuper2区别

b) 数组可以当成指针来用

c) 分类的方法尽量+属于自己前缀区分,万一覆盖了呢

d) 方法替换:替换系统的方法 例如拦截整个项目中所有按钮点击事件

e) hook:钩子函数 拦截系统的方法 塞入自己的实现

f) 类簇(cu):我们看到的类型不一定是他的真实类型 NSString、NSArray、NSDictionary,真实类型是其他类型

g) 转成底层代码的方式
    1) 转成cpp文件(作为参考)
    2) 程序运行起来查看汇编
    3) 转成汇编

a) isKindOfClass // 传入的对象的类对象是否==判断的类对象或者他的子类
b) isMemberOfClass // 传入的对象的类对象是否==判断的类对象
c) super class的返回类型是谁取决于方法调用者是谁即:消息接收者 消息接收者仍然是子类对象,只不过从父类的方法开始寻找方法
c) 底层实现原理

a) 函数调用堆栈的问题
    1) 局部变量分配在栈空间
    2) 栈空间分配,从高地址到低地址
b) 寄存器(存储在cpu里面,相当于一个元件,参数都是存储在这里)比内存的效率更高

原文地址:https://blog.csdn.net/ZZ_IOSdeveloper/article/details/122917020

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任

如若转载,请注明出处:http://www.7code.cn/show_25436.html

如若内容造成侵权/违法违规/事实不符,请联系代码007邮箱suwngjj01@126.com进行投诉反馈,一经查实,立即删除

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注