网络
URLConnetion与URLSession
相同点
- 进行普通的Get/Post请求
- 设置请求路径(创建URL对象)
- 设置请求头和请求体(用URL创建URLRequest)
- 发送请求(URLRequest)
不同点
区别 | URLConnection | URLSession |
---|---|---|
普通任务和上传 | \ | 创建的task都是挂起 状态,需要resume才能执行 |
下载任务 | 整个下载到内存,写入沙盒,可能会出现内存暴涨 | 下载到沙盒的tmp,完成后删除,不会出现内存暴涨 |
请求方法的控制 | 实例化同步发送请求,自动,停止后不能继续访问 | 三个控制方法,取消、暂停、继续,手动 |
断点续传 | 设置HTTPHeaderField的Range开启运行循环,使用NSOutputStream管道流进行数据保存 | 更加便捷 |
配置信息 | 依赖一个全局的配置对象 | 使用构造方法配置 |
OC中浅拷贝与深拷贝
浅拷贝
复制时,引用计数,相当于retain操作,但没有产生新的对象
复制后,源对象和副本对象是同一个对象
深拷贝
复制时,源对象引用计数不变,副本对象引用计数为1,产生了新的对象
复制后,源对象和副本对象是两个不同的对象
retain、copy和MutableCopy的区别
区别 | retain | copy | MutableCopy |
---|---|---|---|
可变对象 | 浅复制 | 深复制 | 深复制 |
不可变对象 | 浅复制 | 浅复制 | 深复制 |
引用计数 | +1 | 浅复制+1 | 不变 |
返回对象 | 保持一致 | 不可变对象 | 可变对象 |
离屏渲染
离屏渲染:在当前用于显示的屏幕缓冲区之外新开辟的一个缓冲区进行渲染
- 创建新缓冲区
- 上下文切换
GPU 会为每一帧重复合成所有的图层,上下文切换发生在每一帧中
图层的以下属性会导致离屏渲染:
- 圆角 cornerRadius 和 maskToBounds 一起使用时
- 遮罩 masks
- 阴影 shadows
一般情况下应该避免离屏渲染,尽量避免使用 layer 的 border、corner、shadow、mask 等
UIImageView 使用 png 图片设置圆角时不会触发离屏渲染
性能优化之光栅化
一个 tableView 中有大量带圆角的视图,当 tableView 快速滑动时,可以看到 GPU 已经被占满,而 CPU 占用量很少。为了避免这种情况,可以尝试开启光栅化 CALayer.shouldRasterize
会消耗额外的内存,一定要避免用在内容是动态变化的图层上,不然它缓存方面的优势就会丧失,而且会让性能变的更糟。
设置 shouldRasterize
的同时也要设置 rasterizationScale
开启光栅化,即手动启动离屏渲染,将离屏渲染的工作交由 CPU 处理
系统架构
- Cocoa Touch layer
- Media layer
- Core Services layer
- Core OS layer
内存分配
栈区(stack)
存储每一个函数在执行的时候都会向 OS 索要资源,内存随着函数的运行分配,随着函数的结束而释放。
申请空间大于栈剩余空间会栈溢出
堆区(heap)
OS 有一个记录空闲内存地址的链表,当系统收到程序的申请时,遍历链表寻找合适堆结点分配给程序,多余部分重新放入空闲链表
全局区(静态区) (static)
- BSS区:存放程序中未初始化全局变量
- 数据区:存放可执行文件中已初始化全局变量(静态变量和全局变量)
常量区
- 存放常量字符串,程序结束后由系统释放
代码区
- 存放函数的二进制代码
- 只读
高地址————————>低地址
| 栈区 | 堆区 | 全局区 | 常量区 | 代码区 |
区别 | 栈 | 堆 |
---|---|---|
管理方式 | 编译器自动完成 | 程序员手动完成(ARC) |
生长方向 | 向低地址扩展 | 向高地址扩展 |
内存连续性 | 连续 | 不连续(链表) |
内存碎片 | 不会产生 | 容易产生 |
分配方式 | 静态(局部变量)动态(alloc) | 动态 |
分配速度 | 快 | 慢 |
存储内容 | 函数参数值,局部变量(Swift 值类型) | 动态分配alloc的内存段(Swift 引用类型) |
空间大小 | 小(固定) | 很大(不固定) |
锁🔒
OSSpinLock 自旋锁
- 全局变量表示锁的可用情况,忙等机制
dispatch_semaphore 信号量
pthread_mutex 互斥锁
- 阻塞线程并睡眠,需要进行上下文切换
pthread_mutex(recursive) 递归锁
- 允许同一个线程在未释放其拥有的锁时反复对该锁进行加锁操作
NSLock
- 封装pthread_mutex
- PTHREAD_MUTEX_ERRORCHECK
NSRecursiveLock 递归锁
- PTHREAD_MUTEX_RECURSIVE
NSConditionLock 条件锁
- 通过条件变量实现
- 阻塞线程,等待数据就绪后唤醒线程
@synchronized
- 使用互斥锁的数组(锁池),通过对对象去哈希值来得到对应的互斥锁
多线程
多线程 | 生命周期管理 | 优点 |
---|---|---|
pthread | 手动 | 跨平台,可移植,使用难度大 |
Thread | 手动 | OO,简单轻量,直接操控线程对象 |
GCD | 自动 | 充分利用设备内核 |
Operation | 自动 | OO,封装GCD |
GCD
同步:阻塞当前线程并等待 Block
中的任务执行完毕才继续
异步:不阻塞
串行:FIFO,GCD依次执行
并发:FIFO,GCD取出放到别的线程
Operation
创建一个 Operation 后,需要调用 start
方法来启动任务,默认 在当前队列同步执行
在 start
方法之前调用addExecutionBlock:
添加任务,在主线程和其它多个线程并发执行
线程同步
- 互斥锁 :给需要同步的代码块加一个互斥锁,可以保证每次只有一个线程访问此代码块
- 同步执行:把多个线程都要执行此段代码添加到同一个串行队列
延迟执行
performSelector:withObject:afterDelay:
(Objective-C)- DispatchQueue.main.asyncAfter
- Timer.scheduledTimer
回到主线程
performSelectorOnMainThread:withObject:waitUntilDone:
(Objective-C)- DispatchQueue.main.async
- OperationQueue.main.addOperation
SDWebImage实现原理
下载图片
- 创建一个继承 NSOperation 的类,添加任务
- 异步下载图片
- 返回主线程刷新UI
加载图片
- 先读取缓存
- 如果缓存无数据,进行下载
- 下载完成,存入缓存
利用下载图片的URL为键,UIImage为值。如有有值的话直接设置图片
利用下载图片的URL为键,Operations 为值。如果没有值创建下载操作,有值继续下载
缓存实现
方式:内存缓存,磁盘缓存
存:先把图片存到内存,再存到磁盘,文件名为URL的md5加密后得到的32位字符串
取:如果内存无图片,把URL用md5加密,再到磁盘搜索
清理缓存
- 遍历缓存目录,删除过期图片
- 统计没有过期的图片,判断是否超过了最大缓存,如果超过,从大到小删除
Copyright © 2019 Weslie. All rights reserved.