总有一天可以躺平的ヾ(◍°∇°◍)ノ゙

Latest

Category和关联对象

Category和关联对象

Category也就是分类,可以在没有类定义的情况下为现有类添加方法、属性、协议,众所周知是不能增加成员变量的,但是是可以通过关联对象给类增加的。 struct category_t { const char *name; classref_t cls; WrappedPtr instanceMethods; WrappedPtr classMethods; struct protocol_list_t *protocols; struct property_list_t *instanceProperties; // Fields below this point are not always present on disk. struct property_list_t *_classProperties; method_list_t *methodsF

By LEMON
内存管理-AutoreleasePool

内存管理-AutoreleasePool

AutoreleasePool(自动释放池)是Objective-C中的一种内存自动回收机制,它可以延迟加入AutoreleasePool中的变量release的时机。 @autoreleasepool { ... }可以通过 clang -rewrite-objc 命令转成C++代码如下 /* @autoreleasepool */ { __AtAutoreleasePool __autoreleasepool; } 然后可以从objc源码中找到__AtAutoreleasePool的定义 struct __AtAutoreleasePool { __AtAutoreleasePool() { atautoreleasepoolobj = objc_autoreleasePoolPush(); } ~__AtAutoreleasePool() { objc_autoreleasePoolPop(atautoreleasepoolobj); } void * atautoreleasepoolobj; }; 这个结构体先

By LEMON
如何为macOS应用开发插件

如何为macOS应用开发插件

本文章只用于学习和交流,转载请注明出处。 玩过越狱手机的应该都了解,iOS的越狱插件是可以为系统或者应用添加一些特色的功能的。越狱插件的开发,已经有完整的工具链,并且插件的加载运行Substrate框架已经为我们做好。 更改应用的功能实现有两种方法,一种是通过反编译工具更改汇编代码后生成新的可执行文件。另一种是写一个动态库,然后注入到可执行文件。第一种适合简单的逻辑修改,毕竟用汇编实现功能是需要很大的工作量的。 第二种要怎么注入呢?了解Mach-O 二进制文件的应该知道,Mach-O 二进制文件Load Commands中的 LC_LOAD_DYLIB 标头告诉 macOS在执行期间要加载哪些动态库 (dylib)。所以我们只需要在二进制文件中添加一条LC_LOAD_DYLIB就可以。而insert_dylib工具已经为我们实现了添加的功能。所以现在唯一需要考虑的就是插件如何开发。 废话不多说,现在就以mac版的迅雷为例开发一款属于我们自己的插件。首先下载最新版本的迅雷(版本5.0.2)。然后用Xcode新建一个macOS下的Framework,如下 新建完目录结构如下,如果

By LEMON
深入分析objc_msgSend尾调用优化

深入分析objc_msgSend尾调用优化

无意间看到了这篇文章 iOS objc_msgSend尾调用优化详解,讲的是在Release模式下,当某函数的最后一项操作是调用另外一个函数,编译器会生成调转至另一函数所需的指令码,而且不会向调用堆栈中推入新的“栈帧”(frame stack),以实现栈帧复用。 栈帧就是一个函数执行的环境:函数参数、函数的局部变量、函数执行完后返回到哪里等等。所以在每一次函数调用之前,需要保存下执行的环境,以确保正常返回到调用位置。下面是- (void)viewDidLoad方法的汇编代码 可以看出在调用[super viewDidLoad]之前,先申请栈空间,然后保存x29和x30寄存器的值,调用结束后恢复寄存器的值,然后平栈。x29寄存器也就是fp寄存器,保存栈底的地址。x30寄存器也就是lr寄存器,保存返回地址。那栈帧复用又是怎么实现的呢?本着知其然知其所以然的精神,深入研究下。用下文章中的例子 - (NSInteger)func1:(NSInteger)num{ if (num >= 2000000) { return num; } return

By LEMON
深入分析弱引用(__weak)

深入分析弱引用(__weak)

__weak 在开发中经常用到,主要是为了解决内存管理中的循环引用。__weak修饰的指针特性是其指向的对象销毁后,会自动置为 nil。 用到__weak基本上分两种情况,一种是先声明再赋值(@property (weak)也是这种),另一种是声明的时候赋值。 NSObject *obj = [NSObject new]; __weak id weak; weak = obj; __weak id weak1 = obj; 新建个项目,在项目中写入以上代码,然后再终端输入以下命令编译成C++源码 xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc -fobjc-arc -fobjc-runtime=ios-8.0.0 "替换为写代码的文件" 可得到以下内容,发现__weak 对应的类型属性都为__attribute((objc_ownership(

By LEMON
编译调试objc4-841.13源码

编译调试objc4-841.13源码

从苹果开源网站https://opensource.apple.com/releases/下载最新源码,这里是objc4-841.13版本,各个版本需要处理的问题差别不是很大。编译环境如下 * 系统: macOS 12.4 (21F79) * 工具: Xcode 13.4.1 (13F100) * 源码: objc4-841.13 下载好代码解压,打开后编译objc Target。下面按照错误出现的顺序,依次解决。 1、unable to find sdk 'macosx.internal' 分别选objc和objc-trampolines两个target,然后把Base SDK选为macOS。 2、'sys/reason.h' file not found 头文件缺失,只要找到对应的头文件添加到工程中就可以解决,首先在工程的根目录创建include文件夹,然后在工程的Build

By LEMON
Objective-C类结构分析(class_rw_t)

Objective-C类结构分析(class_rw_t)

上一篇分析了cache_t的结构和怎么缓存方法的,这里继续分析objc_class中的class_data_bits_t,搜索可以找到主要结构如下 struct class_data_bits_t { friend objc_class; uintptr_t bits; class_rw_t* data() const { return (class_rw_t *)(bits & FAST_DATA_MASK); } bool isAnySwift() { return isSwiftStable() || isSwiftLegacy(); } }; 可以看出,结构体里面只有一个bits,然后主要方法就是获取class_rw_t,和判断是不是Swift的类。 看标题就知道,这篇文章的重点就是class_rw_t,源码中搜索找到结构体定义 struct class_

By LEMON
Objective-C类结构分析(cache_t)

Objective-C类结构分析(cache_t)

在Objective-C中Class底层实现其实是一个objc_class类型的结构体 /// An opaque type that represents an Objective-C class. typedef struct objc_class *Class; 查看源码,可以看到objc_class的结构如下 struct objc_class : objc_object { Class superclass; cache_t cache; // formerly cache pointer and vtable class_data_bits_t bits; // class_rw_t * plus custom rr/alloc flags } objc_class继承于objc_object结构体,objc_

By LEMON
Tagged Pointer 详解

Tagged Pointer 详解

Tagged Pointer是苹果在64bit设备引入的一种技术,是用于优化NSNumber、NSDate、NSString等小对象的存储。 查看objc4源码可以找到只要64位系统才支持 #if __LP64__ //文件objc-internal.h line 283 #define OBJC_HAVE_TAGGED_POINTERS 1 #endif 同时也可以找到,Tagged Pointer 所支持的类型,一个objc_tag_index_t类型的枚举,如下 // 60-bit payloads OBJC_TAG_NSAtom = 0, OBJC_TAG_1 = 1, OBJC_TAG_NSString = 2, OBJC_TAG_NSNumber = 3, OBJC_TAG_NSIndexPath = 4,

By LEMON
Objective-C中self和super的区别

Objective-C中self和super的区别

self和super在开发中经常遇到,最常见的场景就是 self=[super init],很明显这是两个不同的关键字,肯定是有区别的。 在写区别之前,先新建个工程,然后创建个Ghost类文件,在文件中写入以下方法并调用。 - (void)run{ NSLog(@"%@", [self class]); NSLog(@"%@", [super class]); NSLog(@"%@", [self superclass]); NSLog(@"%@", [super superclass]); } 会神奇的发现,self和super调用相同方法,输入的结果也是一样的。 为什么呢?Objective-C的底层是C/C++封装的,把上面代码转成C++代码以更好的分析。转代码之前,先把代码简化为以下,可以更方面查看。 - (void)run{ [self class]; [super class]; [self superclass]; [super superclass]; } 打开终端,

By LEMON
搭建自己的云笔记-为知笔记私有部署

搭建自己的云笔记-为知笔记私有部署

公有云笔记有很多,就不一一列举。这些云笔记各有各的特点,不足的是数据不可控,并且部分功能需要付费才能使用。 为知笔记也算是老牌的笔记了,但是知道的人却不是很多。为知笔记服务端提供了docker镜像,只需要简单几步,就可以将为知笔记服务端部署在自己的服务器上。选择它的原因主要有以下几点。 1、多端丰富,PC、Mac、iOS、安卓都有,且支持多端同步。 2、有加密功能,有些个人资料可以加密处理。 3、笔记支持多级目录,并且支持多格式导出。 4、私有版5 用户以下免费使用。 我的服务器是腾讯云的云主机,系统是Ubuntu Server 18.04.1 64位。因为为知笔记是docker镜像的,所以装之前需要先安装docker。首先通过终端连接到服务器,然后在终端按顺序输入以下命令。 1、先卸载旧版本的docker; sudo apt-get remove docker docker-engine docker.io containerd runc 2、

By LEMON
深入理解isa指针

深入理解isa指针

实例对象的isa指针指对象的类,类对象的isa指针指向对象的元类,这种说法对吗? 对,但也不完全对。因为在arm64架构之前,isa确实只存储着Class、Meta-Class对象的内存地址,但是在之后苹果对isa进行了优化,变成了一个共用体结构,使其能用位域存储更多的信息。而指向Class的指针需要按位与个ISA_MASK才可以获取到。 上图是一张很经典的指针指向图,虽然已经不完全正确,但是还是可以作为参考的。 上一篇文章提到,isa指针被优化成union isa_t类型,源码中搜索可以在objc-private.h文件中找到定义,去除方法简化后的代码如下 union isa_t { uintptr_t bits; private: Class cls; public: struct { ISA_BITFIELD; // defined in isa.h }; }; 然后再isa.h文件里面找到ISA_BITFIELD的定义,忽略x86和模拟器,把定义替换到以上代码中,可以变成如下 union isa_t {

By LEMON
京ICP备15024336号-4