1. 什么是逃逸闭包?
当闭包作为一个实际参数传递给一个函数或者变量的时候,我们就说这个闭包逃逸了,可以在形式参数前写 @escaping 来明确闭包是允许逃逸的。
- 非逃逸闭包、逃逸闭包,一般都是当做参数传递给函数
- 非逃逸闭包:闭包调用发生在函数结束前,闭包调用在函数作用域内
- 逃逸闭包:闭包有可能在函数结束后调用,闭包调用逃离了函数的作用域,需要通过@escaping声明
2. 沙盒目录结构是怎样的?
沙盒结构
-
Documents:常用目录,iCloud备份目录,存放数据,这里不能存缓存文件,否则上架不被通过
-
Library
- Caches:存放体积大又不需要备份的数据,SDWebImage缓存路径就是这个
- Preference:设置目录,iCloud会备份设置信息
-
tmp:存放临时文件,不会被备份,而且这个文件下的数据有可能随时被清除的可能
3.说一下 http中的 get 和 post 区别?
- get 一般用于从服务端获取数据,post 用于向服务端发送数据
- get 参数拼接在 url 地址里面, post 参数则放在其包体里,post 比 get 稍安全,隐秘
- get 可以被缓存,可以存储在浏览器浏览历史中
4.HTTPS连接过程简述
- 客户端向服务端发起 https 请求
- 服务器(需要申请 ca 证书),返回证书(包含公钥)给客户端
- 客户端使用根证书验证 服务器证书的有效性,进行身份确认
- 客户端生成对称密钥,通过公钥进行密码,发送给服务器
- 服务器使用私钥进行 解密,获取对称密钥
- 双发使用对称加密的数据进行通信
5.weak 和 assign 的不同点
weak策略在属性所指的对象遭到摧毁时,系统会将weak修饰的属性对象的指针指 向nil,在OC给nil发消息是不会有什么问题的;- 如果使用
assign策略在属性所指 的对象遭到摧毁时,属性对象指针还指向原来的对象,由于对象已经被销毁,这时候就产生了野指针,如果这时候在给此对象发送消息,很容易造成程序崩溃。 assigin可以用于修饰非OC对象,而weak必须用于OC对象
6. 遇到过BAD_ACCESS的错误吗?
BAD_ACCESS 报错属于内存访问错误,会导致程序崩溃, 错误的原因是访问了野指针(悬挂指针)。
7. 说一下iOS 中的APNS,远程推送原理?
Apple push Notification Service,简称 APNS,是苹果的远程消息推送,原理如下:
- iOS 系统向APNS服务器请求手机端的
deviceToken - App 接收到手机端的 deviceToken,然后传给 App 对应的服务器.
- App 服务端需要发送推送消息时, 需要先通过 APNS 服务器
- 然后根据对应的 deviceToken 发送给对应的手机
8. 在iOS开发中,UIView的frame和bounds在以下哪种情况下是不相等的?
当视图进行了旋转或缩放变换时
9, iOS 开发 内存泄漏常见场景及检测方案
-
核心本质:内存泄漏是对象引用计数无法归 0。 核心原因是“循环引用”和“未及时释放强引用”;
-
必记场景:Block 循环引用、NSTimer 泄漏、代理 strong 修饰、通知/KVO 未移除,
各场景的解决方案必须熟练;
10,iOS多线程之GCD
同步任务嵌套同步任务,会引发阻塞,原因在于,第一个任务执行完毕的条件是第二个任务执行完毕,而第二个任务执行完毕的条件是第一个任务执行完毕,因此二者相互等待,无法结束。
11, 造成死锁的四个条件:
- 互斥条件:某个资源一次只能被一个线程占用。
- 占有且等待:一个线程占有一个资源,同时等待其他资源。
- 不可剥夺:线程所持有的资源不能被强制剥夺。
- 循环等待:两个或多个线程形成一种循环等待关系。
12,前端请求
前端请求表面看只是“调接口拿数据”,但真正完整的过程,远不止这一句。它涉及用户操作、事件触发、浏览器网络通信、服务器处理、数据返回、前端解析和页面渲染,是一整条完整链路。
13,进程和线程
进程和线程的核心区别在于:
进程是资源分配的基本单位,而线程是 CPU 调度的基本单位。简单来说,进程像一个独立的工厂,拥有自己的场地和资源;线程则是工厂里的工人,共享工厂资源但独立执行任务。
资源与内存分配
进程:拥有独立的地址空间和系统资源(如内存、文件句柄),进程间相互隔离,一个进程崩溃通常不会影响其他进程 。 线程:不拥有系统资源,仅拥有少量运行必需资源(如栈、寄存器),共享所属进程的全部资源(如内存、打开的文件)。
14,Source0 和 Source1
Source0和Source1是 iOS/macOS 中 RunLoop 的两种输入源(CFRunLoopSourceRef),核心区别在于触发机制与唤醒能力:Source0 处理应用层手动触发事件(不能主动唤醒休眠线程),Source1 处理基于 Mach Port 的系统/内核事件(能主动唤醒休眠线程)。**
核心定义与功能对比
-
Source0(非基于 Port 的事件源)
- 本质:仅包含回调函数指针(
version 0context),无端口机制。 - 职责:处理 App 内部生成的事件,如
performSelector:afterDelay:、UI 触摸事件的上层分发、自定义业务逻辑触发。 - 唤醒特性:无法主动唤醒休眠的 RunLoop;需先调用
CFRunLoopSourceSignal标记待处理,再手动调用CFRunLoopWakeUp才能执行回调。 - 典型场景:按钮点击响应、手势识别后的业务逻辑、线程间同进程的任务调度。**
- 本质:仅包含回调函数指针(
-
Source1(基于 Mach Port 的事件源)
- 本质:包含 Mach Port 端口号和回调函数(
version 1context),由内核管理。 - 职责:接收系统内核、其他进程或线程通过端口发送的消息,如硬件事件底层捕获、跨进程通信(IPC)、网络数据到达通知。
- 唤醒特性:能主动唤醒休眠的 RunLoop;当端口有消息时,内核直接中断线程使其立即处理回调。
- 典型场景:屏幕触摸底层信号接收、
dispatch_async主队列任务、系统通知、Socket 底层数据读取。
- 本质:包含 Mach Port 端口号和回调函数(
工作流程关键差异
- 触发流程:Source0 需“标记 + 手动唤醒”两步;Source1 仅需“端口发消息”一步,内核自动触发。
- 事件流向:硬件事件通常先由 Source1 捕获(内核态),转化为应用层事件后交由 Source0 处理(用户态)。
- 生命周期:Source0 单次触发后常被移除;Source1 端口可持续监听,支持重复触发。**
简言之,Source0 负责“应用想做的事”,Source1 负责“系统通知你做的事”。两者协同确保 RunLoop 在休眠时节能、有事时即时响应。
15,避免大图 OOM 的黄金法则: “磁盘下载、子线程解码、按需缩放、分块渲染” 。
务必记住:图片文件大小(File Size)不等于内存占用(Memory Footprint) 。内存占用取决于像素总数 × 每像素字节数。通过 ImageIO 控制解码尺寸,是从根源上解决大图内存问题的最佳方案。
1. 基础下载:异步写入文件(避免内存爆炸)
不要使用 NSData *data = [NSData dataWithContentsOfURL:url],这会将几 MB 甚至几十 MB 的数据一次性载入内存。
推荐做法:使用 NSURLSessionDownloadTask
-
优势:系统直接以流式方式写入磁盘临时文件,内存占用极低。
-
代码逻辑:
- 创建
NSURLSessionDownloadTask。 - 在回调
didFinishDownloadingToURL:中获取临时文件路径。 - 将临时文件移动(
moveItemAtPath)到你的缓存目录(如Library/Caches)。
- 创建
- 高效解码与缩放:ImageIO 框架(避免主线程卡顿)
直接从文件读取 UIImage (imageWithContentsOfFile) 会在主线程进行解码,且默认加载全分辨率像素。对于大图,必须在子线程解码并按需缩放。
推荐做法:使用 CGImageSource
优势:支持指定最大像素尺寸解码,避免将 4000x3000 的图片解码进内存,只解码屏幕需要的 400x300。
关键参数:kCGImageSourceThumbnailMaxPixelSize。