MENU

iOS 面试题汇总

April 21, 2019 • Read: 306 • iOS

网络

URLConnetion与URLSession

相同点

  • 进行普通的Get/Post请求
  1. 设置请求路径(创建URL对象)
  2. 设置请求头和请求体(用URL创建URLRequest)
  3. 发送请求(URLRequest)

不同点

区别URLConnectionURLSession
普通任务和上传\创建的task都是挂起状态,需要resume才能执行
下载任务整个下载到内存,写入沙盒,可能会出现内存暴涨下载到沙盒的tmp,完成后删除,不会出现内存暴涨
请求方法的控制实例化同步发送请求,自动,停止后不能继续访问三个控制方法,取消、暂停、继续,手动
断点续传设置HTTPHeaderField的Range开启运行循环,使用NSOutputStream管道流进行数据保存更加便捷
配置信息依赖一个全局的配置对象使用构造方法配置

OC中浅拷贝与深拷贝

浅拷贝

复制时,引用计数,相当于retain操作,但没有产生新的对象

复制后,源对象和副本对象是同一个对象

深拷贝

复制时,源对象引用计数不变,副本对象引用计数为1,产生了新的对象

复制后,源对象和副本对象是两个不同的对象

retain、copy和MutableCopy的区别

区别retaincopyMutableCopy
可变对象浅复制深复制深复制
不可变对象浅复制浅复制深复制
引用计数+1浅复制+1不变
返回对象保持一致不可变对象可变对象

离屏渲染

离屏渲染:在当前用于显示的屏幕缓冲区之外新开辟的一个缓冲区进行渲染

  1. 创建新缓冲区
  2. 上下文切换

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 引用类型)
空间大小小(固定)很大(不固定)

锁🔒

img

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实现原理

下载图片

  1. 创建一个继承 NSOperation 的类,添加任务
  2. 异步下载图片
  3. 返回主线程刷新UI

加载图片

  1. 先读取缓存
  2. 如果缓存无数据,进行下载
  3. 下载完成,存入缓存

利用下载图片的URL为键,UIImage为值。如有有值的话直接设置图片

利用下载图片的URL为键,Operations 为值。如果没有值创建下载操作,有值继续下载

缓存实现

方式:内存缓存,磁盘缓存

存:先把图片存到内存,再存到磁盘,文件名为URL的md5加密后得到的32位字符串

取:如果内存无图片,把URL用md5加密,再到磁盘搜索

清理缓存

  1. 遍历缓存目录,删除过期图片
  2. 统计没有过期的图片,判断是否超过了最大缓存,如果超过,从大到小删除
Last Modified: May 23, 2019
Archives Tip
QR Code for this page
Tipping QR Code