iOS 整体架构
iOS UIView 和 CALayer
UIView 和 CALayer 的关系
iOS-UIView和CALayer的关系 - 简书
iOS 中 UIView 和 CALayer 的关系 - 掘金
- UIView 是UIKit 中的类,继承于UIResponse,可以响应事件。
- CALayer 是 QuartzCore 中的类,继承于NSObject,负责绘制内容、动画,不能响应事件。
CALayer anchorPoint 和 Position
了解CALayer隐式动画
响应者链机制及其应用
史上最详细的iOS之事件的传递和响应机制-原理篇 - 简书
iOS响应者链、事件的传递 - 简书
事件的传递: Hittest 和 PointInside
当一个事件发生后,事件会从父控件传给子控件,也就是说由UIApplication -> UIWindow -> UIView -> subview, 从 SubView数组最后一个开始hittest, 以上就是事件的传递,也就是寻找最合适的view的过程。
事件的响应: touchsBegin
接下来是事件的响应。首先看SubView能否处理这个事件,如果不能则会将事件传递给其上级视图(SubView的superView);如果上级视图仍然无法处理则会继续往上传递;一直传递到视图控制器view controller,首先判断视图控制器的根视图view是否能处理此事件;如果不能则接着判断该视图控制器能否处理此事件,如果还是不能则继续向上传 递;(对于第二个图视图控制器本身还在另一个视图控制器中,则继续交给父视图控制器的根视图,如果根视图不能处理则交给父视图控制器处理);一直到 window,如果window还是不能处理此事件则继续交给application处理,如果最后application还是不能处理此事件则将其丢弃
在事件的响应中,如果某个控件实现了touches...方法,则这个事件将由该控件来接受,如果调用了[supertouches….];就会将事件顺着响应者链条往上传递,传递给上一个响应者;接着就会调用上一个响应者的touches….方法
override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
if isHidden == true || alpha < 0.05 || isUserInteractionEnabled == false {
return super.hitTest(point, with: event)
}else{
if self.point(inside: point, with: event) {
return super.hitTest(point, with: event)
}else{
//1.有subView时交给subView 去响应
for subview in self.subviews{
let coverPoint = self.convert(point, to: subview)
return subview.hitTest(coverPoint, with: event)
}
//2.没有subView时交给自己来响应,也就是说你无论在哪儿点击都会响应(扩大点击区域)
//当然这里如果你想扩大到一定的返回,可以在此处加限制
let isResponse:Bool = false
if isResponse {
return self
}else {
return nil
}
//3.如果你不想当没有subView时就随便响应,j就返回nil
return nil
}
}
}
了解UITouch 和 UIEvent
应用
1. hittest 扩大按钮点击范围: iOS 扩大UIButton的点击范围 - 简书
@implementation CustomButton
- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event {
// 扩大点击区域的宽度和高度
CGFloat expandWidth = 20.0;
CGFloat expandHeight = 20.0;
// 负值会让响应区域扩大
CGRect largerArea = CGRectInset(self.bounds, -expandWidth, -expandHeight);
// 返回点是否在扩展后的区域内
return CGRectContainsPoint(largerArea, point);
}
@end
2. 管理点击事件
UIResponder 的 nextResponder属性:响应链之nextResponder - 简书
动画
iOS开发系列--让你的应用“动”起来 - KenshinCui - 博客园
iOS动画-CAAnimation使用详解 - 简书
动画类型
- CALayer(bounds,position,anchorPoint,transform等)
- Core Animation(基础动画,关键帧动画,动画组,转场动画,逐帧动画)
- UIView动画封装(基础动画,关键帧动画,转场动画)
应用
按钮缩放、抖动动画(使用CAKeyframe实现)
iOS呼吸动画 | 迈腾大队长
https://www.cnblogs.com/sundaysgarden/articles/9252348.html
Lottie 和 PAG
从解码渲染层面对比 PAG 与 lottie - 简书
配置文件
Lottie: Json
PAG: 自研二进制文件
了解Lottie Json 文件大概内容,如何修改
性能优化
iOS - 性能优化 - 简书
iOS面试题:对程序性能的优化你有什么建议? - 简书
内存优化
深入探索iOS 内存优化
内存管理-内存分区
iOS 内存五大区 - 简书
- 堆区:是由程序员分配和释放,用于存放运行中被动态分配的内存段。大小不定,可增加和缩减。
- 栈区:栈是由编译器分配和释放,用于存放程序临时创建的变量、函数的参数、局部变量等。
- 全局(静态)区:是编译时分配的内存空间,在程序运行过程中,此内存中的数据一直存在,程序结束后由系统释放。
static
修饰的变量(全局变量)始终保存到常量区。 - 常量区:是编译时分配的内存空间,在程序结束后由系统释放。存放的是常量,是一块特殊的区域。
- 代码区:用来存放函数的二进制代码,它是可执行程序在内存中的镜像。代码段需要防止在运行时被非法修改,只允许读操作,不允许写操作。
内存问题
iOS 内存优化之工具介绍 - 掘金
iOS 内存泄漏排查方法及原因分析 - 简书
- 内存泄漏:是指申请的内存空间使用完毕之后未回收,主要由循环引用引起,例如block 里引用self,delegate 没有使用weak 修饰,Timer 定时器没有 invalidate, 置为 nil
- 野指针:是指引用一个已经释放的内存空间,例如assign 修饰对象,对象创建即释放,只剩一个指针。
- 内存溢出:是指程序在申请内存时,没有足够的内存空间供其使用。
内存问题检测
iOS 内存泄露、野指针调试技巧_weixin_30515513的博客-CSDN博客
- 野指针:选中Edit Scheme,并点击 Run -> Diagnostics -> Enable Zombie Objects 设置
完 之 后,重新运行。
- 内存泄漏:Analyzer(静态分析);MLeaksFinder (第三方工具);Instruments Leaks (动态检测);排除法
引用计数(ARC, MRC)
+1:alloc, retain, copy,mutableCopy,new
-1:release
引用计数为0,对象释放; 谁引用,谁释放
属性修饰符
IOS中(assign,retain,copy,weak,strong)的区别以及nonatomic的含义
MRC: assign,retain,copy
ARC: strong,weak
readwrite, nonatomic
Weak 和 Unowned
weak
- 用于避免强引用循环。
- 当引用的对象被释放后,weak引用会自动被设置为nil,避免了悬挂指针(dangling pointers)。
- 可以在声明时使用可选类型(optional)来表示weak引用,因为它可能为nil。
unowned
- 也用于避免强引用循环。
- 不会被自动设置为nil,所以在对象被释放后,如果你访问了一个unowned引用,会导致野指针(野引用)错误。
- 通常用于你确切知道引用的对象在引用生命周期内不会被释放的情况,否则会导致崩溃。
卡顿优化
卡顿原因
iOS 保持界面流畅的技巧 | Garan no dou
iOS 底层 - 性能优化之CPU、GPU - 简书
iOS 底层原理 - 性能优化 - 知乎
计算机系统中 CPU、GPU、显示器是协同工作的。CPU 计算好显示内容(如视图的创建、布局计算、图片解码、文本绘制等)提交到 GPU,由 GPU 进行变换、合成、渲染,GPU 渲染完成后将渲染结果放入帧缓冲区,随后视频控制器会按照 VSync 信号逐行读取帧缓冲区的数据,经过可能的数模转换传递给显示器显示。
优化方案
CPU
- 耗时操作放入子线程;如图片解码、尺寸计算、文本绘制等;
- 控制线程的最大并发数量;
- 提前计算好布局,在有需要的时候一次性调整对应属性,不要多次修改;
- 尽量用轻量级的对象 如:不用处理事件的 UI 控件可以考虑使用 CALayer;
- 不要频繁地调用
UIView
的相关属性 如:frame、bounds、transform 等;
GPU