https://www.jianshu.com/p/a81d48e0e44a
https://www.cnblogs.com/heluan/p/8620312.html
https://www.jianshu.com/p/25b762d58e66
http://www.runoob.com/w3cnote/ten-sorting-algorithm.html 十大经典算法
https://www.jianshu.com/p/95d224c4d13e 七大查找算法
https://www.jianshu.com/p/19d7b1afcdcc
https://www.jianshu.com/p/915356e280fc
https://www.jianshu.com/p/502c5da1f170
https://www.jianshu.com/p/ad9f1f3971d7
https://www.jianshu.com/p/60352a5eb940
self 是类的隐藏参数,指向当前调用方法的这个类的实例。而 super 是一个 Magic Keyword, 它本质是一个编译器标示符,和 self 是指向的同一个消息接受者。
上面的例子不管调用[self class]还是[super class],接受消息的对象都是当前 Son *xxx 这个对象。而不同的是,super是告诉编译器,调用 class 这个方法时,要去父类的方法,而不是本类里的。
当使用 self 调用方法时,会从当前类的方法列表中开始找,如果没有,就从父类中再找;而当使用 super 时,则从父类的方法列表中开始找。然后调用父类的这个方法。
当调用 [self class] 时,实际先调用的是 objc_msgSend函数,
第一个参数是 Son当前的这个实例,然后在 Son 这个类里面去找 - (Class)class这个方法,
没有,去父类 Father里找,
也没有,最后在 NSObject类中发现这个方法。
而 - (Class)class的实现就是返回self的类别,故上述输出结果为 Son。
而当调用 [super class]时, 会转换成objc_msgSendSuper函数。
第一步先构造 objc_super 结构体,
结构体的第一个成员就是 self 。 第二个成员是 (id)class_getSuperclass(objc_getClass(“Son”)) , 实际该函数输出结果为 Father。
第二步是去 Father这个类里去找 - (Class)class,没有,然后去NSObject类去找,找到了。
最后内部是使用 objc_msgSend(objc_super->receiver, @selector(class))去调用, 此时已经和[self class]调用相同了,故上述输出结果仍然返回 Son。
22 编译过程
当一个xcode工程build之后一般会执行如下几个步骤:
iOS编译采用Clang作为编译器前端,LLVM作为编译器后端。流程如下:
Clang的任务:预处理、词法分析、语法分析、语义分析、静态分析、生成中间代码。
预处理:以#开头的代码预处理。包括引入的头文件和自定义宏。
词法分析:每一个.m源文件的声明和定义从string转化为特殊的标记流。
语法分析:将标记流解析成一颗抽象语法树( abstract syntax tree-AST)。
静态分析:包含类型检查和其他检查。
中间代码生成:生成LLVM代码。
LLVM的任务:将代码进行优化并产生汇编代码。
汇编器:将可读的汇编代码转换为机器代码,最终创建一个目标对象.o文件。
链接器的任务:把目标文件和库相连,最终输出可运行文件:a.out。
链接:https://www.jianshu.com/p/65901441903e
dyld加载过程
https://blog.csdn.net/shihuboke/article/details/73930935
符合oc 继承类 初始化规范 super 同样也是这样, [super init] 去self 的super 中调用init super 调用 superSuper 的init 。直到根类 NSObject 中的init ,根类中init 负责初始化 内存区域 向里面添加 一些必要的属性,返回内存指针, 这样 延着继承链 初始化的内存指针 被从上 到 下 传递,在不同的子类中向块内存添加 子类必要的属性,直到 我们的 A 类中 得到内存指针,赋值给slef 参数, 在if (slef){//添加A 的属性 }
struct objc_super {
id receiver;
Class superClass;
};
self和super底层实现原理:
- 当使用 self 调用方法时,会从当前类的方法列表中开始找,如果没有,就从父类中再找;而当使用 super 时,则从父类的方法列表中开始找,然后调用父类的这个方法。
- 当使用 self 调用时,会使用 objc_msgSend 函数: id objc_msgSend(id theReceiver, SEL theSelector, ...)。第 一个参数是消息接收者,第二个参数是调用的具体类方法的 selector,后面是 selector 方法的可变参数。以 [self setName:] 为例,编译器会替换成调用 objc_msgSend 的函数调用,其中 theReceiver 是 self,theSelector 是 @selector(setName:),这个 selector 是从当前 self 的 class 的方法列表开始找的 setName,当找到后把对应的 selector 传递过去。
- 当使用 super 调用时,会使用 objc_msgSendSuper 函数:id objc_msgSendSuper(struct objc_super *super, SEL op, ...)第一个参数是个objc_super的结构体,第二个参数还是类似上面的类方法的selector。
lookUpImpOrForward
会返回一个imp
,它的函数实现比较长,但是注释写的非常清楚。它的实现主要由以下几步(这里直接从缓存获取开始):
cache_getImp
从缓存中获取方法,有则返回,否则进入第2步;getMethodNoSuper_nolock
从类的方法列表中获取,有加入缓存中并返回,否则进入第3步;for
循环,沿着类的父类一直往上找,直接找到NSObject为止。如果找到返回,否则进入第4步;_class_resolveMethod
,如果失败,进入第5步;_objc_msgForward_impcache
进行方法转发,如果找到便加入缓存;如果没有就crash。上述过程中有几个比较重要的函数:
链接:
https://juejin.im/post/5c87a218f265da2dd868cfcd
https://www.jianshu.com/p/fdd8f5225f0c
18 缓存淘汰策略FIFO、LFU、LRU 算法
(1)缓存数据和目标数据的一致性问题。
(2)缓存的过期策略(机制)。
其中,缓存的过期策略涉及淘汰算法。常用的淘汰算法有下面几种:
(1)FIFO:First In First Out,先进先出
(2)LRU:Least Recently Used,最近最少使用
(3)LFU:Least Frequently Used,最不经常使用
链接:https://www.jianshu.com/p/660f61084d9b
https://www.cnblogs.com/sunsky303/p/9214223.html
https://www.jianshu.com/p/4cd5509eec3d
https://www.jianshu.com/p/33e572da4b58
https://www.cnblogs.com/argenbarbie/p/5401133.html
https://www.jianshu.com/p/0b8f6a5e66bc
参考:
https://objccn.io/issue-6-1/
https://objccn.io/issue-6-3/
https://objccn.io/issue-6-2/
https://www.jianshu.com/p/65901441903e
http://blog.chinaunix.net/uid-31439230-id-5763397.html
https://blog.csdn.net/Future_One/article/details/81882359
1 预处理
符号化 (Tokenization)
宏定义的展开
#include 的展开
2 语法和语义分析
将符号化后的内容转化为一棵解析树 (parse tree)
解析树做语义分析
输出一棵抽象语法树(Abstract Syntax Tree* (AST))
3生成代码和优化
将 AST 转换为更低级的中间码 (LLVM IR)
对生成的中间码做优化
生成特定目标代码
输出汇编代码
4 汇编器
将汇编代码转换为目标对象文件。
5 链接器
将多个目标对象文件合并为一个可执行文件 (或者一个动态库)
https://www.jianshu.com/p/adef1ef4ff39
线程栈
线程的每个方法被执行的时候,都会同时创建一个帧(Frame)用于存储本地变量表、操作栈、动态链接、方法出入口等信息。每一个方法的调用至完成,就意味着一个帧在VM栈中的入栈至出栈的过程。如果线程请求的栈深度大于虚拟机所允许的深度,将抛出StackOverflowError异常;如果VM栈可以动态扩展(VM Spec中允许固定长度的VM栈),当扩展时无法申请到足够内存则抛出OutOfMemoryError异常。
原文:https://blog.csdn.net/u013851082/article/details/70314778
https://www.jianshu.com/writer#/notebooks/15534033/notes/42885788
https://www.jianshu.com/p/c67964d85e91
参考: https://www.jianshu.com/p/8ea1e5169d7a 《objc源码解析-ObjectiveC对象结构》
参考:https://blog.csdn.net/u013378438/article/details/80493158 《基本数据结构:objc_object & objc_class》
Tagged Pointer 的引用主要解决内存浪费和访问效率的问题。所以其有以下特点:
如此可见,Apple 引入了 Tagged Pointer 不仅仅节省了64位处理器的占用内存空间,还提高了运行效率。
使用注意点
https://www.jianshu.com/p/dcbf48a733f9
https://www.jianshu.com/p/c9089494fb6c
https://www.jianshu.com/p/e354f9137ba8
1, objc_object中的isa 指的是对象的类;
2, objc_class中的isa只的是类的元类;
3, superClass是一层层集成的,到最后NSObject的superClass是nil.而NSObject的isa指向根元类,这个跟元类的isa指向它自己,而它的superClass是NSObject,也就是最后形成一个环,这个环让我想起了先有鸡还是先有蛋的问题.
4, mateClass也是相互继承的.
5, 这个逻辑就想着objc_class的struct,里面有个isa属性,还有个super_class属性,他俩都是指针,其实在objc_class的定义中也能看出来,每一个objc_class都有isa,但是不一定会有super_class,近三天每天想一次.
https://www.jianshu.com/p/20f1251916b9
https://www.jianshu.com/p/9e975a1cab93
https://www.jianshu.com/p/4ae681091e2a
在32位系统中:
int 占4个字节
long 占4个字节
NSInteger 是int的别名,占4个字节
long long 占8个字节
int32_t 是int的别名,占4个字节
int64_t 是long long的别名,占8个字节
在64位系统中:
int 占4个字节
long 占8个字节
NSInteger 是long的别名,占8个字节
long long 占8个字节
int32_t 是int的别名,占4个字节
int64_t 是long long的别名,占8个字节
由于long和NSInteger的字节数变了,所以在兼容的时候可能会导致溢出
原文:https://blog.csdn.net/zhao18933/article/details/46925675
1. kCFRunLoopDefaultMode: 默认 mode,通常主线程在这个 Mode 下运行。
2. UITrackingRunLoopMode: 追踪mode,保证Scrollview滑动顺畅不受其他 mode 影响。
3. UIInitializationRunLoopMode: 启动程序后的过渡mode,启动完成后就不再使用。
4: GSEventReceiveRunLoopMode: Graphic相关事件的mode,通常用不到。
5: kCFRunLoopCommonModes: 占位mode,作为标记DefaultMode和CommonMode用。
https://segmentfault.com/a/11900000024003291、CFMessagePort 2、XPC可以被libxpc C API访问,或者是NSXPCConnection OC API 3、XPC提供了一个便捷的方法来从dispatch_data_t数据类型进行转换,这样从GCD到XPC的工作流程就简化了: 4、NSPasteboard 5、Distributed Notifications:APICFNotificationCenterGetDistributedCenter
6、LightMessaging :http://iphonedevwiki.net/index.php/LightMessaging ,https://github.com/rpetrich/LightMessaging
https://www.jianshu.com/p/2fe076e5e255 小心NSTimer中的内存泄漏
利用 NSTimer 的 userInfo 传入 block
在 Nstimer 的回调中,使用 block ,用block 循环引用的方式 处理 。
https://www.jianshu.com/p/a1f377dfc85a
https://www.jianshu.com/p/3b7efa02bdf4
关于app启动优化,可以从几方面入手:
1.关于UITableView
(1)善于使用UITableViewCell的重用机制
(2)优化UITableViewCell高度计算
2 懒加载(延迟加载)
3 关于图片的处理
(1)缓存图片 一个是用imageNamed,二是用imageWithContentsOfFile。
(2)调整图片大小
(3)代码渲染 or 直接获取
图片的解码字节对齐。
(4)图片尺寸的大小 和 imageView 的大小不一致 也会消耗性能,用ImageIO 进行优化
4 数据处理
在项目开发中,我们会使用到各种格式的数据,例如 JSON、XML 等。还有各种各样的数据结构,例如数组、链表、字典、集合等。使用正确的数据格式和使用正确的数据结构,会减少我们的资源消耗。
(1)选择正确的数据格式
App与网络进行交互时,常常采用 JSON 或者 XML 类型的数据格式。
(2)选择正确的数据结构
不同的数据结构,处理数据的速度是不同的。
数组 NSArray NSMutableArray:有序的一组值。使用索引来查询很快,使用值查找很慢, 插入/删除很慢。
字典 NSDictionary NSMutableDictionary:存储键值对。用键来查找比较快。
集合 NSSet NSMutableSet:无序的一组值。用值来查找很快,插入/删除很快。
5 View的处理
(1)避免使用过于复杂的xib
(2)正确设置View的背景
(3)设定Shadow Path
如果用下面代码给 view.layer 添加一个shadow:
这会使Core Animation 不得不在后台得出图形并加好阴影之后再去渲染,这会开销很大。
如果使用shadowPath则会避免这种问题:
6 合理使用Autorelease Pool
7 正确处理缓存
8 iOS使用的是低内存处理机制Jetsam,这是一个基于优先级队列的机制。
9 CAShapeLayer是一个通过矢量图形而不是bitmap来绘制的图层子类。用CGPath来定义想要绘制的图形,CAShapeLayer会自动渲染。它可以完美替代我们的直接使用Core Graphics绘制layer,对比之下使用CAShapeLayer有以下优点:
渲染快速。CAShapeLayer 使用了硬件加速,绘制同一图形会比用 Core Graphics 快很多。
高效使用内存。一个 CAShapeLayer 不需要像普通 CALayer 一样创建一个寄宿图形,所以无论有多大,都不会占用太多的内存。
不会被图层边界剪裁掉。
不会出现像素化。
10 画布ImageContext 消耗内存大 通过 @autoreleasepool 来解决
11 光栅化,是把GPU的操作转到CPU上了,生成位图缓存 。当 shouldRasterize 设成 true 时,layer 被渲染成一个 bitmap,并缓存起来,等下次使用时不会再重新去渲染了。实现圆角本身就是在做颜色混合(blending),如果每次页面出来时都blending,消耗太大,这时shouldRasterize = yes,下次就只是简单的从渲染引擎的 cache 里读取那张 bitmap,节约系统资源。
可见,如果要节约内存,尽量少用光栅化。
12 临时变量过多,建议使用autoreleasepool 以便及时释放;
https://www.jianshu.com/p/5e95e70948f7
https://www.jianshu.com/p/1f6bc977d97c
https://mp.weixin.qq.com/s/q1jufAuZytF3yi6tE2jY0g 先弄清楚这里的学问,再来谈iOS内存管理与优化(二)
https://www.jianshu.com/p/ba45f5539e4e
1. 画布ImageContext 消耗内存大 通过 @autoreleasepool 来解决
2. image I/O 创建省略图
https://www.jianshu.com/p/de7b6aede888 iOS的5种图片缩略技术以及性能探讨
https://www.jianshu.com/p/bee0d5efc964 drawRect 内存暴增原因,如何优化绘图
内存恶鬼drawRect - 谈画图功能的内存优化
1、CGContextDrawImage方式(CoreGraphics)
它接受一个原始的位图参数 imageRef ,最终返回一个新的解压缩后的位图 newImage ,中间主要经过了以下三个步骤:
使用 CGBitmapContextCreate 函数创建一个位图上下文;
使用 CGContextDrawImage 函数将原始位图绘制到上下文中;
使用 CGBitmapContextCreateImage 函数创建一张新的解压缩后的位图。
2、CGImageGetDataProvider方式(ImageIO)
1.CGImageSourceCreateWithData(data) 创建ImageSource。
2.CGImageSourceCreateImageAtIndex(source) 创建一个未解码的 CGImage。
3.CGImageGetDataProvider(image) 获取这个图片的数据源。
4.CGDataProviderCopyData(provider) 从数据源获取直接解码的数据。
ImageIO 解码发生在最后一步,这样获得的数据是没有经过颜色类型转换的原生数据(比如灰度图像)。
链接:https://www.jianshu.com/p/e9843d5b70a2