- 博客(45)
- 收藏
- 关注
原创 RxSwift - 实现一个MVVM架构的TableView
架构在在实际开发中被广泛应用,它让代码结构清晰美观,易于阅读维护,同时也弥补了。中会有相应的获取数据以及处理数据的方法,然后将数据传输到。进行绑定,实现动态修改数据时更新UI。,赋值时进行UI内容样式设置。层,首先有个简单的Cell。模型简单表示了一个商品的。,它有一个数据有属性。
2024-05-30 11:18:06
616
原创 Swift - 可选项(Optional)
如果对值为nil的可选项(空盒子)进行强制解包,将会产生运行时错误。遍历数组,将遇到的整数都加起来,如果遇到负数或者非数字,停止遍历。被包装的数据(将盒子里装的东西取出来),需要使用感叹号。= nil || b!= nil && b!通过打印结果可以看出是否是可选类型。这种方式在每次使用的时候,需要使用。的可选项,在后续使用过程中它将会。num1、num3为nil的情况。多重可选项,相当于装了多层盒子。,把值赋给一个临时的常量(可选项是否包含值,再进行。a是nil,b是可选项。a为nil、b都可选项。
2024-04-28 22:56:04
1271
3
原创 Swift - 枚举
场景:日期(digit表示使用年月日形式,string表示使用字符串形式)场景: 分数(points表示实际得分,grade表示分数的等级)可以使用MemoryLayout获取数据类型占用的内存大小。注意:原始值不占用枚举变量的内存。来表示每一个case就行,要获取。的值关联存储在一起,会非常有用。必要时let也可以改为var。的原始值的枚举又是怎样的?如果枚举的原始值类型是。other(1字节)
2024-04-28 22:54:51
852
6
原创 Swift - 流程控制
关于case匹配问题,属于模式匹配(Pattern Matching)的范畴,以后会再次详细展开讲解。由于已确定answer是Ansewer类型,因此可以省略Answer。字符、字符串也能使用区间运算符,但默认不能用在for-in中。前面写的区间并没有写类型,编译器自动推断类型了。a...b,a
2024-04-26 23:50:03
807
1
原创 Swift - 基础语法
let doubleDecimal = 125.0 // 十进制,等价于1.25e2(1.25*10的2次方)。let doubleHexadecimal2 = 0xFp-2 // 十六进制,意味着15x2^-2,相当于十进制的3.75。let doubleHexadecimall = 0xFp2 // 十六进制,意味着15x2^2,相当于十进制的60.0。let intHexadecimal = 0x11 //时间六进制。let intDecimal = 17 // 十进制。//整数、浮点数转换。
2024-04-25 12:57:32
961
2
原创 iOS - 多线程-读写安全
操作,那是非常危险的事情,会造成数据错乱。操作其实不会影响原数据,因此是可以允许。可以解决问题,但是针对该场景,将其与其它线程隔离开。
2024-04-24 11:37:10
768
原创 iOS - 多线程-atomic
atomicsettergettergettersetter不能保证getsetgetset外面atomicgetset@oubijiexi。
2024-04-24 11:35:31
444
原创 iOS - 多线程的安全隐患
如果系统不知道持有者所在的线程,则无法知道应该提高谁的优先级,也就无法解决反转问题。的线程在等待锁的时候,内核无法知道该提高那个线程的优先级(QoS);方法中,假设该方法中已经加锁,同时会调用另一个也需要加锁的方法。为了方便调试,我们做个简单封装,将需要加锁的代码放在。相关线程的优先级来解决优先级反转的问题,如。子类,然后重写上述方法,实现各自的加锁方式。的时候,系统不知道哪个线程会调用。业务场景中,可能需要不同线程间的。,所以系统也不知道owner信息。个异步线程并发执行,每个线程卖。
2024-04-23 13:54:47
1376
原创 iOS - 多线程-GCD-队列组
开发过程中,有时候想实现这样的效果。并发执行完成后,再并发执行任务。可以使用GCD的队列组来实现。并发执行,完成后执行任务。,达到这样的效果:任务。
2024-04-23 13:53:34
936
1
原创 iOS - 多线程-GCD
GNUstep是GNU计划的项目之一,它将Cocoa的OC库重新开源实现了一遍。虽然GNUstep不是苹果官方源码,但还是具有一定的参考价值。队列(Concurrent Dispatch Queue)看似是在没有延迟的情况下执行,实际上因为该方法是基于。队列(Serial Dispatch Queue)添加一个定时器,但是因为此时我们是在。这时候都有打印,只不过打印顺序。主要影响:能不能开启新的线程。主要影响:任务的执行方式。上面的例子中,主要是考察。,这次打印顺序是正常的。
2024-04-22 12:53:24
923
原创 iOS - Runloop在实际开发中的应用
当scrollView 滚动时,定时器就停止了。使用NSTimer创建一个定时器,循环打印。,避免每次都要创建、销毁带来不必要的开销。在 ViewController中使用。执行任务,可能希望一个线程可以。
2024-04-22 12:28:13
448
原创 iOS - Runloop的运行逻辑
系统事件捕捉:从用户点击屏幕到应用处理触摸事件,先是由。屏幕点击事件(系统事件),然后再包装成。和Autorelease pool。,不同于while循环那种,而是。Runloop休眠,是通过。于Runloop,它们是。即将进入睡眠状态时触发。
2024-03-29 22:56:59
927
1
原创 iOS - Runtime-API
开发过程中经常会用到Runtime,比如:执行结果:2.2.3 销毁一个类void objc_disposeClassPair(Class cls)2.2.4 获取isa指向的ClassClass object_getClass(id obj)2.2.5 设置isa指向的ClassClass object_setClass(id obj, Class cls)2.2.5.1 示例执行结果:执行结果:执行结果:BOOL class_addProperty(Class cls
2024-03-28 23:04:38
1217
原创 iOS - LLVM的中间代码(IR)
- 全局变量% - 局部变量alloca - 在当前执行的函数的堆栈帧中分配内存,当该函数返回到其调用者时,将自动释放内存i32 - 32位4字节的整数align - 对齐load - 读出,store 写入icmp - 两个整数值比较,返回布尔值br - 选择分支,根据条件来转label,不根据条件跳转的话类似gotolabel - 代码标签call - 调用函数@oubijiexi。
2024-03-28 23:01:15
248
原创 iOS - Runtime-消息机制-objc_msgSend()
本章主要介绍消息机制-objc_msgSend的执行流程,分为消息发送动态方法解析消息转发三个阶段,每个阶段可以做什么。还介绍了super的本质是什么,如何调用的在动态方法解析阶段,方法是可以给消息接受者动态增加一个`方法实现在消息转发阶段,方法是可以重新返回一个消息接受者,相当于是让另一个人来处理这个方法。但是,来到方法后,可以使用方法签名自定义更复杂的业务。
2024-03-27 23:18:32
1642
原创 iOS - Runtime - Class-方法缓存(cache_t)
来缓存曾经调用过的方法,可以提高方法的查找速度。调用的方法,会把该方法缓存到这个。才找到方法实现,也会把方法混存到。Class内部结构中有个方法。查找,或者当前类没找到继续到。调用的方法,最终是在他的。再调用此方法,直接在。
2024-03-26 23:46:18
748
原创 iOS - Runtime - Class的结构
前面我们学习OC对象的时候,了解了class类对象、meta-class元类对象实际上,class类对象、meta-class元类对象底层结构体都是class元类对象可以认为是特殊的类对象。他们底层结构是一样的,只不过存储的内容有所区别。
2024-03-26 23:43:51
962
原创 iOS - Runtime-isa详解(位域、union(共用体)、位运算)
本章主要了解Runtime相关内容,苹果对isa做了哪些优化,位域、union(共用体)又是如何运用的要想学习Runtime,首先要了解它底层的一些常用数据结构,比如isa指针在arm64架构之前,isa就是一个普通的指针,存储着ClassMeta-Class对象的内存地址从arm64架构开始,对isa进行了优化,变成了一个共用体(union)结构,还使用位域来存储更多的信息利用好位域的话,可以使程序运行高效节省内存,操作系统级别的东西很多都会使用在IM系统的开发中,就使用了位域。
2024-03-25 13:07:39
1472
原创 OC对象 - Block解决循环引用
本章将会通过一个循环引用案例,分析其原因,以及在ARCMRC下的解决方案通常使用__weak来解决循环引用。使用__weak修饰的对象销毁后,指针会自动设置为nil。和__block虽然也可以解决环引用问题,但是在修饰的对象销毁后,指针不会自动设置为nil,因此如果还去使用这个对象就会出现异常。__block需要保证 block 有被调用,否则还是会循环引用。
2024-03-25 13:06:40
598
原创 OC对象 - Block内存管理
block变量包装成一个对象,对象对应的结构体如下。,并且在修改值的时候,它也是通过访问包装对象的。在栈上时,他指向的是栈上的自己。复制到堆上后,不管使用栈上的。变量用结构体的指针,堆上的。指向的还是自己本身的指针。,再访问将要操作的变量。使用过程中,是可能从。是指向自己的指针,当。拷贝到堆上后,栈上的。
2024-03-24 14:58:29
835
1
原创 OC对象 - Block修改变量
_block可以用于解决block内部无法修改auto变量值的问题__block不能修饰全局变量、静态变量(static)编译器会将__block变量包装成一个对象这个对象对应的是结构体结构体中有个指向自身的指针。
2024-03-24 14:56:03
915
1
原创 OC对象 - Block-对象类型的auto变量
当block内部访问了对象类型的auto变量时如果block是在栈上,将不会对auto变量产生强引用如果block被拷贝到堆上会调用block内部的copy函数copy函数内部会调用函数_Block_object_assign函数会根据auto变量的修饰符strong、weak、__unsafe_unretained)做出相应的操作,形成强引用(retain)或者弱引用如果block从堆上移除会调用block内部的dispose函数dispose函数内部会调用函数。
2024-03-23 15:26:12
865
1
原创 OC对象 - Block的类型
当运行如下代码,却发现访问了 auto 变量的 block 却是。类型,__NSStackBlock__调用了copy后是。通过下面示例,验证了block作为函数返回值时是。我们已经知道,访问了auto变量的block是。操作(具体规则后面章节讲),我们先把项目设置为。这是因为,现在项目默认是启用。,可以看到最终是继承自。此时的 block 是。
2024-03-22 23:59:23
481
原创 OC对象 - Block 的本质
代码块,开发中常用来封装一段代码,在想要执行的时候再调用执行,也常用来做传值、事件传递等等,是不可或缺的一个特性。其实就是把我们 block 里面所写的代码封装成函数传进去。他实际上就是帮我们调用了刚刚初始化时传入的保存在。Desc则是block的描述信息,对应结构体。此时block里面的代码就被调用执行了。转成c++代码,来验证下它的底层结构。,可以看到此处代码传入的值是。我们初始化block后,通过。则表示 block 的大小。写一个最基础的block。构造方法接收两个参数。
2024-03-21 22:50:03
420
1
原创 OC对象 - 关联对象(如何给分类添加成员变量)
Category(分类)的底层结构中,没有成员变量(ivar),因此不能给分类添加成员变量;在分类里面声明的属性,只会生成 get/set 方法的声明,没有方法的实现。给分类添加的成员变量,他并不是保存在该结构体下,因为Category(分类)的底层结构中并没有。所以我们不能直接给分类添加成员变量,但是可以间接实现,那就是使用。关联对象是通过这四个核心对象共同完成的,他们之间的关系是这样的。可以看到我们像正常使用对象的属性一样,使用分类中创建的属性。,这点我们在使用的时候需要注意。我们上面的示例,使用的。
2024-03-20 23:29:22
1335
1
原创 OC对象 - +load、initialize方法
initialize和+load的很大区别是,+initialize是通过objc_msgSend进行调用的,所以有以下特点。从类文件列表看到,ZSXPerson在其两个分类的后面编译的,但是它的+load始终是最先调用的。走了runtime机制调用,我们知道,子类收到消息时,如果自身找不到方法实现,会到父类中继续查找。+load方法是根据方法地址直接调用,并不是经过objc_msgSend函数调用。发送消息,因为分类方法覆盖了类的方法,会先执行父类分类。注:如果有分类的情况,发送消息,先执行父类。
2024-03-20 23:27:45
494
1
原创 OC对象 - Category(分类)
我们有必要记住这个分类数据的合并顺序,下面将通过示例代码来验证。假设有多个ZSXPerson的分类,他们都重写了。可以拖动这个列表,来调整类的编译顺序,此时我们把。假设我们有ZSXPerson类,其中有。方法,有一个ZSXPerson的分类,这是当前的类文件,将按从上往下的顺序。
2024-03-19 01:19:30
443
1
原创 OC对象 - KVC
我们已经没有任何 set 方法了,但是 KVO 监听依然触发了。此时它不会查找成员变量,因此找不到对应的 key 赋值,抛异常了。我们主要验证下没有set方法的情况下,是否会触发KVO监听。我们在ZSXPerson.m中实现下这两个方法。原理,已经能确定是会触发KVO监听的。找不到方法,接下来按顺序查找成员变量。可以看到 KVO 监听也是会触发的。我们清楚KVO的原理,以及KVC。,最后查不到对应方法抛异常了。,最后查不到对应方法抛异常了。验证了 成员变量按顺序查找。
2024-03-19 01:17:29
644
1
原创 OC对象 - KVO
利用RuntimeAPI动态生成一个子类,并且让instance对象的isa指向这个全新的子类当修改instance对象的属性时,会调用Foundation的函数父类原来的setter内部会触发监听器(Oberser)的监听方法( observeValueForKeyPath:ofObject:change:context:)
2024-03-18 12:43:23
802
原创 OC对象的分类
之所以传入不同对象,返回不同的类对象,关键在意 getIsa()方法。详细原因了解后面isa的指向后即可清楚。// meta-class 元类对象。获取的并不是元类对象,而是类对象。
2024-03-17 17:01:09
373
1
原创 OC对象 - NSObject对象占用多少内存
我们知道NSOjcect底层实现中,结构体里面仅有Class isa一个成员,那么,NSObject对象是否就是占用8个字节呢?先说结果:一个NSObject对象占用的是16字节,但实际利用的只有 8 个字节我们来验证一下本节我们主要会用到一下这两个函数// 获得NSObject类的实例对象所占用的大小// 获得obj指针指向内存的大小return 0;我们分别用这两个函数,打印内存大小class_getInstanceSize打印的是8字节,malloc_size 打印的是16。
2024-03-17 02:24:32
502
1
空空如也
空空如也
TA创建的收藏夹 TA关注的收藏夹
TA关注的人