3~5年开发经验的 iOS工程师 应该知道的内容~本文总结以下内容
- 网络基础
- AFNetWorking
- SDWebImage
导航
- 对象
- 类对象
- 分类
- runtime
- 消息与消息转发
- KVO
- KVC
- 多线程
- 锁
- runloop
- 计时器
- 视图渲染和离屏渲染
- 事件传递和响应链
- crash处理和性能优化
- 编译流程和启动流程
- 内存管理
- 野指针处理
- autoreleasePool
- weak
- 单例、通知、block、继承和集合
- 网络基础
- AFNetWorking
- SDWebImage
网络基础
什么是 TCP / UDP
?
TCP
:传输控制协议。面向连接的,建立连接需要经历三次握手,是可靠的传输层协议。UDP
:用户数据协议。是面向无连接的,数据传输快但不可靠,它只管发,不管收不收得到。
TCP
和UDP
的区别
TCP
是传输控制协议,是面向字节流的可靠传输,通过分组编号,确认应答,超时重发,流量控制和拥塞控制机制保证数据分组正确有序完整的传输到接收方UDP
是用户数据包协议,不具有TCP的以上机制来保证可靠传输,是以数据报的形式发出,从最下层发出后,它认为发送成功,是不具有保序 正确和完整传输的性质。
TCP是如何保证可靠性
- 1、校验和,检验范围包括TCP首部及数据部分。将报文分段,所有段反码相加,最终结果为全1
- 2、确认应答与序列号,按序,不缺,去重,多次发送,一次确认
- 3、超时重传
- 4、连接管理,三次握手四次挥手
- 5、流量限制,16位的窗口。
- 6、拥塞控制,慢启动、拥塞避免、拥塞发生、快重传、快恢复
TCP拥塞控制
- 1)慢启动
- 2)拥塞避免
- 3)拥塞发生
- 4)快速恢复
什么是XMPP?
- XMPP是以XML为基础的开放式实时通信协议。
HTTP建立连接的过程?
- 三次握手
TCP三次握手和四次挥手?
三次握手
- 1、客户端向服务端发起请求链接,发送报文,
seq=x
,客户端进入SYN_SENT状态 - 2、服务端收到请求链接,回复确认报文,
seq=y
,ACK=x+1
,并且服务端进入到SYN_RCVD状态 - 3、客户端收到确认报文后,回复报文,
ACK=y+1
,此时客户端进入到ESTABLISHED,服务端收到用户端发送过来的确认报文后,也进入到ESTABLISHED状态,此时链接创建成功 四次挥手 - 1、客户端向服务端发起关闭链接请求,并停止发送数据
- 2、服务端收到关闭请求时回复,收到,然后停止接收数据
- 3、当服务端发送数据结束之后,向客户端发起关闭链接请求,并停止发送数据
- 4、客户端收到关闭请求时回复,收到,然后停止接收数据
为什么需要三次握手?
- 防止已失效的连接请求报文段突然又传送到了服务端,产生错误。
- 假设不采用三次握手,只要服务器收到链接请求并发出确认,新的连接就建立了。
- 假设现在有一个已失效的连接请求报文段延迟收到了,服务端误认为是客户端要建立新连接,于是回复了确认报文并认为成功建立了连接。实际上客户端并没有建立连接的打算,不会处理服务端的确认报文也不会发送数据。服务端此时一直等待数据,这样就浪费掉很多资源。
为什么需要四次挥手?
TCP
是全双工通信的,服务端接收到客户端的关闭请求时,可能还在向客户端发送着数据。- 只能先回复一个收到,发送完原来的数据后再发送关闭请求。
HTTP
长/短连接
HTTP
请求是在TCP
连接上进行发送的,TCP
的连接分为:长连接,短连接HTTP
请求发送的时候,先创建一个TCP连接,然后在这个TCP
连接上,发送HTTP
的请求并接受返回数据。- 一次
HTTP
请求结束了,请求端跟服务端商量是否关闭TCP
连接。 - 短链接:
- 关闭,下次请求的时候重新创建连接,好处是能减少服务端与客户端并发连接数
- 长链接:
- 不关闭,
TCP
连接一直开着会有一定的消耗,如果还有请求可以直接在这个TCP
上发送,省去三次握手的消耗 - 网址的并发量可能比较大,当创建连接的次数很多时,它实际的开销可能比维持一个长连接的开销还要高一些。
- 长连接可以设置
timeout
,这个长连接一定时间内没有请求会自动关闭
- 不关闭,
HTTP的安全性
http
本身并不具备加密功能,http
报文使用明文方式发送就可能被窃听
HTTP常见状态码
- 1xx:指示信息–表示请求已接收,继续处理。
- 2xx:成功–表示请求已被成功接收、理解、接受。
- 3xx:重定向–要完成请求必须进行更进一步的操作。
- 4xx:客户端错误–请求有语法错误或请求无法实现。
- 5xx:服务器端错误–服务器未能实现合法的请求。
HTTP的请求过程?
- 1、建立
TCP
连接 - 2、客户端发送请求命令
- 3、客户端发送请求头
- 4、服务器应答
- 5、服务器回应头信息
- 6、服务器发送数据
- 7、断开连接
HTTP和TCP的区别
TCP
协议是传输层协议,主要解决数据如何在网络中传输HTTP
是应用层协议,主要解决如何包装数据。
HTTP2 和 1 的区别
- 新的二进制格式(
Binary Format
),HTTP1.x
的解析是基于文本。基于文本协议的格式解析存在天然缺陷,文本的表现形式有多样性,要做到健壮性考虑的场景必然很多,二进制则不同,只认0和1的组合。基于这种考虑HTTP2.0
的协议解析决定采用二进制格式,实现方便且健壮。 - 多路复用(
MultiPlexing
),即连接共享,即每一个request
都是是用作连接共享机制的。一个request
对应一个id
,这样一个连接上可以有多个request
,每个连接的request
可以随机的混杂在一起,接收方可以根据request id
将request
再归属到各自不同的服务端请求里面。 - header压缩,
HTTP1.x
的header
带有大量信息且每次都发送,HTTP2.0
使用encoder
来减少需要传输的header
大小,通讯双方各自cache
一份header fields
表,既避免了重复header的传输,又减小了需要传输的大小。 - 服务端推送(
server push
),同SPDY
一样,HTTP2.0
也具有server push
功能。
HTTP和HTTPS有什么区别?
HTTP
协议是一种使用明文数据传输的网络协议。HTTPS
协议可以理解为HTTP
协议的升级,就是在HTTP
的基础上加密数据后再发送到服务器。这样就算数据被截获,也能保证信息的安全。
HTTPS的SSL加密方式?
https
采用对称加密和非对称加密结合的方式来进行通信。- 对称加密: 加密和解密都是同一个钥匙
- 非对称加密:密钥成对,分为公钥和私钥,公钥加密需要私钥解密,私钥加密需要公钥解密
HTTPS传输数据的过程?
- 使用HTTPS需要保证服务端配置好安全证书
- 客户端发送请求到服务端,服务端返回证书和公钥
- 客户端拿到证书验证安全性,然后生成一个随机数,用公钥加密随机数后发送给服务端
- 服务端用私钥解密得到随机数,再用这个随机数作为私钥对传输的数据加密,最后发送数据
- 客户端拿到传输的数据后用之前生成的随机数对其解密获取数据
SSL建立连接的过程是什么?
- 首先客户端向服务器发送自身的
SSL
版本以及加密参数给服务器 - 服务器返回自己的
SSL
版本和参数以及数字证书包括了服务器的公钥 - 客户端生成浏览器会话秘钥通过公钥进行加密返回给服务器,服务器通过私钥解密出会话秘钥
- 客户端再发送一个报文通知服务器以后通过该会话秘钥进行加密传输,并发送加密报文表示我方SSL链接建立完成
- 服务器也回复相同的表示自己也建立连接完成
什么是中间人攻击
- 中间人攻击(Man-in-the-MiddleAttack,简称MITM攻击)
- 攻击者与通讯的两端分别创建独立的联系,并交换其所收到的数据,使通讯的两端认为他们正在通过一个私密的连接与对方直接对话,事实上整个会话被攻击者完全控制。
- 客户端发送请求到服务端,请求被中间人截获。
- 服务器向客户端发送公钥1。
- 中间人拦截公钥1,伪造公钥2发送给客户端。
- 客户端收到公钥2后,生成加密hash值发给服务器。
- 中间人拦截服务器数据,使用私钥2解码获得真数据,用公钥1加密修改后的假数据返回服务端
- Charles抓包原理就是中间人攻击
防范中间人攻击
- 需要找一个通信双方都信任的第三方来为双方确认身份。类似公证处用公章为信件盖上章,证明这封信由原发件人发出
- CA,数字证书认证机构,就是负责颁发数字证书证明身份的
- 申请人将一些必要信息(包括公钥、姓名、电子邮件、有效期)等提供给 CA
- CA用自己的私钥对信息的散列值加密,形成数字签名,附在证书最后
- 将数字证书颁发给申请人,申请人就可以使用 CA 的证书向别人证明身份
- 相当于传送双方的信件都需要通过CA盖章,中间人攻击能伪造真实公钥但是无法
- 收件方收到数字证书之后,用 CA 的公钥解密证书最后的签名得到加密之前的散列值
- 计算数字证书中信息的散列值,将两者进行对比,只要散列值一致,就证明这张数字证书是有效且未被篡改过的
MD5、SHA1、SHA256的区别
- 这3种本质都是摘要函数
- MD5 是 128 位
- SHA256 是 256 位
- SHA1 是 160 位 ,已经不再安全,不使用
GET请求的过程
- 三次握手,第三次发送请求头和数据
- 服务端返回200
POST请求过程
- 三次握手,第三次发送请求头
- 服务端返回100
- 客户端发送数据
- 服务端返回200
GET和POST请求的区别
POST
比GET
更安全,GET把请求参数拼接到URL后面,POST把请求参数放在请求体里面GET
比POST
请求速度快,因为少了一次确认过程
DNS及解析流程
- 本地 - 根 - 顶级 - 权限 - 主机IP
解释一下 TTL
time to live
,指定数据报被路由器丢弃之前允许通过的网段数量TTL
是由发送主机设置的,转发IP数据包时,要求路由器至少将TTL
减小 1。TTL
的主要作用是避免包在网络中的无限循环和收发,节省了网络资源,并能使IP包的发送者能收到告警消息。
HTTP的header都有哪些?
HTTP
分为请求消息和响应消息,请求方式不同,header
也不同- 请求消息格式:
- 请求方法
- URL
- 协议版本
- 响应消息格式:
- 状态响应码
- 协议版本
请求头都有什么内容?
- 1、请求的地址域名和端口,
Host: [www.study.com](www.study.com)
- 2、连接类型,
Connection: keep-alive
- 3、
http
自动升级到https
,Upgrade-Insecure-Requests:1
- 4、浏览器的用户代理信息
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.96 Safari/537.36
- 5、浏览器支持的请求类型,
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
- 6、浏览器能处理的压缩代码,
Accept-Encoding: gzip, deflate, sdch
- 7、浏览器当前设置语言,
Accept-Language: zh-CN,zh;q=0.8,en;q=0.6
- 8、请求参数长度,
Content-Length: 29
- 9、强制要求服务器返回最新的文件内容,也就是不走缓存,返回的200,
Cache-Control: max-age=0
- 10、请求来源地址,
Origin: <http://www.study.com>
- 11、原始的url,
Referer: <http://www.study.com/day02/01-login.html>
用户是如何通过url地址访问到服务器的,它怎么知道要访问哪个浏览器
- DNS域名解析,通过这一步还原IP(迭代查询,递归查询)
- TCP连接,三次握手
- HTTP请求,请求报文主要包括请求行,请求头,请求正文
- 处理请求返回HTTP响应,返回Response,主要包括状态码,响应头,响应报文三个部分
- 页面渲染
- 关闭连接,四次挥手
在浏览器中输入URL,发生的事情都有什么?
- 输入URL后,
URL = 协议 + 域名 + 服务器资源位置
- 在通信子网中是通过
IP
为标志进行分组转发,因此需要通过DNS
进行解析出IP
- 封装
HTTP
消息请求下发到传输层,在传输数据之前需要双方简历TCP
链接 - 链接建立完成后,根据
TCP
协议进行首部封装,然后下发到网络层根据IP
协议进行IP
数据单元封装, - 到数据链路层根据
ARP
协议对IP
进行转换为MAC
地址,然后加帧首帧尾巴,进行帧封装, - 然后到物理层转为
bit
流进行通信传输到目的主机,自底向上进行解封装到达应用层, - 根据资源位置,在服务器上查询到
web
对象,将HTML
文档加到响应消息返回给客户端浏览器。
上述只是协议建立通信的过程,得到服务器返回的内容后做了什么?
- 客户端渲染服务器返回的内容
- 和服务端断开
TCP
连接(四次挥手)
验证一个字符串是否为合法的ipv4地址
- 1、校验是否有3个小数点;
- 2、以小数点将字符分割为4部分,校验每部分的字符;
- 3、校验该部分转为
int
值之后, 满足0<n<255,而且第一部分不为0
网络的七层协议
- 1、物理层,网卡。数据单位是bit
- 2、数据链路层,交换机,负责节点间的通信传输,保障数据传输可靠性。数据单位是帧
- 3、网络层,创建节点之间的传输逻辑链路,通过路由实现不同局域网间的通信。数据单位是数据包
- 4、传输层,建立了主机端到端服务,处理数据包错误和保证次序。
tcp、udp。ipv6
传输效率高就和这层有关 - 5、会话层,维护两个结点间的传输连接,确保点到点传输不中断,以及管理数据交换。
- 6、表示层,设备的数据格式和网络标准格式的转换
- 7、应用层,提供各种网络服务,比如文件服务器、数据库服务、电子邮件与其他网络软件服务。
你平时怎么解决网络请求的依赖关系:当一个接口的请求需要依赖于另一个网络请求的结果
- 方法1:在上一个网络请求的响应回调中进行下一网络请求的激活
- 方法2:线程:
NSOperation
操作依赖和优先级,操作B依赖于操作 - 方法3:
GCD
信号量 - 方法4:
GCD group
SDWebImage
SDWebImage是怎么做缓存的?
- 缓存采用了二级缓存策略。 图片缓存的时候, 在内存和磁盘中都缓存
- 其中内存缓存是用
NSCache
实现的。
SDWebImage缓存步骤:
- 0、下载图片
- 1、将图片缓存在内存中
- 2、判断图片的格式
png
或jpeg
,将图片转成NSData
数据 - 3、获取图片的存储路径, 其中图片的文件名是通过传入
URLKey
经过MD5
加密后获得的 - 4、将图片存在进磁盘中
SDWebImage如何获取图片
- 1、在内存缓存中找
- 2、如果内存中找不到, 会去默认磁盘目录中寻找, 如果找不到,在去自定义磁盘目录中寻找
- 3、如果磁盘也找不到就会下载图片
- 4、获取图片数据之后, 将图片数据根据图片的类型从
NSData
转化UIImage
。 - 5、默认对图片进行解压缩,生成位图图片
- 6、将位图图片返回
SDWebImage图片是如何被解压缩的?
- 1、判断图片是否是动态图片,如果是,不能解压缩
- 2、判断图片是否透明,如果是,不能解压缩
- 3、判断图片的颜色空间是不是RGB如果不是、不能解压缩
- 4、根据图片的大小创建一个上下文
- 5、将图片绘制在上下文中
- 6、从上下文中读取位图图像,该图像就是解压缩后的图像
- 7、将位图图像返回
SDWebImage怎么使用NSCache
NSCache
是缓存专用的系统类NSCache
是线程安全的- 内存不足,
NSCache
会自动释放掉存储的对象。
//名称
@property (copy) NSString *name;
//NSCacheDelegate代理
@property (nullable, assign) id<NSCacheDelegate> delegate;
//通过key获取value,类似于字典中通过key取value的操作
- (nullable ObjectType)objectForKey:(KeyType)key;
//设置key、value
- (void)setObject:(ObjectType)obj forKey:(KeyType)key; // 0 cost
/*
设置key、value
cost表示obj这个value对象的占用的消耗?可以自行设置每个需要添加进缓存的对象的cost值
这个值与后面的totalCostLimit对应,如果添加进缓存的cost总值大于totalCostLimit就会自动进行删除
感觉在实际开发中直接使用setObject:forKey:方法就可以解决问题了
*/
- (void)setObject:(ObjectType)obj forKey:(KeyType)key cost:(NSUInteger)g;
//根据key删除value对象
- (void)removeObjectForKey:(KeyType)key;
//删除保存的所有的key-value
- (void)removeAllObjects;
/*
当NSCache缓存的对象的总cost值大于这个值则会自动释放一部分对象直到占用小于该值
非严格限制意味着如果保存的对象超出这个大小也不一定会被删除
这个值就是与前面setObject:forKey:cost:方法对应
*/
@property NSUInteger totalCostLimit; // limits are imprecise/not strict
/*
缓存能够保存的key-value个数的最大数量
当保存的数量大于该值就会被自动释放
非严格限制意味着如果超出了这个数量也不一定会被删除
*/
@property NSUInteger countLimit; // limits are imprecise/not strict
/*
这个值与NSDiscardableContent协议有关,默认为YES
当一个类实现了该协议,并且这个类的对象不再被使用时意味着可以被释放
*/
@property BOOL evictsObjectsWithDiscardedContent;
@end
//NSCacheDelegate协议
@protocol NSCacheDelegate <NSObject>
@optional
//上述协议只有这一个方法,缓存中的一个对象即将被删除时被回调
- (void)cache:(NSCache *)cache willEvictObject:(id)obj;
@end**
复制代码
countLimit**
这个属性就是设置最大缓存数量。 和栈一样遵循先进先出(FIFO
)原则。
countLimit
设置为5,当缓存第6个对象的时候,第一个会缓存会被移除,所以这有一个风险。
为什么通过key去取值的时候,一定要判断一个获取的对象是否为nil?
- 就因为很有可能某些对象被释放(顶)掉了。
NSCache里面缓存的对象,在什么场景下会被释放?
NSCache
自身释放了,其中存储的对象也就释放了。- 手动调用释放方法
removeObjectForKey、removeAllObjects
- 缓存对象个数大于
countLimit
- 缓存总消耗大于
totalCostLimit
- 程序进入后台会释放
- 收到内存警告,不一定立刻释放,根据
discardContent
协议
SDWebImage如何解决tableView的复用时出现图片错乱问题的呢
- 设置新图片前调用
UIImageView+WebCache
的[self sd_cancelCurrentImageLoad]
使用SDWebImage过程中碰到的问题?怎么解决?
- 开发项目的时候涉及到图像处理的问题,具体现象是
SDWebImage
下载超清大图出现崩溃 - 原因是库的内部下载成功后会使用
decodeImageWithImage
这个方法解压缩并缓存图片 - 用此方法加载
tableview/collectionview
中多张超清大图的时候,会导致内存暴涨,很有可能crash - 因为获取到
UImage
的时候还不是位图,在主线程赋值的时候才会绘制位图,高清会导致卡顿 - 解决办法是对于高清图片,禁止直接解压缩并缓存,自己压缩绘制出位图后再赋值。
- SD4.X的解决办法
[[SDImageCache sharedImageCache] setShouldDecompressImages:NO];
[[SDWebImageDownloader sharedDownloader] setShouldDecompressImages:NO];
- SD5.0 及以上的解决办法
SDWebImageAvoidDecodeImage添加了这个枚举,意思是在子线程程解压缩图片
[self.imageView sd_setImageWithURL:self.url placeholderImage:[UIImage imageNamed:@"logo"] options:SDWebImageAvoidDecodeImage];
复制代码
AFNetworking
AFNetworking的源码架构?
- 网络通信模块(
NSURLSession
) - 网络状态监听模块(
Reachability
) - 网络通信安全策略模块(
Security
) - 网络通信信息序列化/反序列化模块(
Serialization
)
为什么AFN3.0中需要设置self.operationQueue.maxConcurrentOperationCount = 1
- 2.x是基于
NSURLConnection
的,其内部实现要在异步并发,所以不能设置1。 - 3.x是基于
NSURLSession
其内部是需要串行的鉴于一些多线程数据访问的安全性考虑, 设置这个达到串行回调的效果。
AFNetworking 2.0 和3.0 的区别?
- AFN3.0移除了所有的
NSURLConnection
- AFN3.x是基于
NSURLSession
的 - AFN3.0使用
NSOperationQueue
代替AFN2.0的常驻线程
2.x版本为什么需要常驻线程
- 在请求完成后我们需要对数据进行一些序列化处理,或者错误处理。如果我们在主线中处理这些事情很明显是不合理的。不仅会导致UI的卡顿,甚至受到默认的
RunLoopMode
的影响,我们在滑动tableview
的时候,会导致时间的处理停止。 - 这里时候我们就需要一个子线程来处理事件和网络请求的回调了。但是,子线程在处理完事件后就会自动结束生命周期,这个时候后面的一些网络请求得回调我们就无法接收了。所以我们就需要开启子线程的
RunLoop
来保存线程的常驻。 - 当然我们可以每次发起一个请求就开启一条子线程,但是这个想一下就知道开销有多大了。所以这个时候保活一条线程来对请求得回调处理是比较好的一个方案。
3.x版本为什么不需要常驻线程?
- 在3.x的AFN版本中使用的是
NSURLSession
进行封装。对比于NSURLConnection
,NSURLSession
不需要在当前的线程等待网络回调,而是可以让开发者自己设定需要回调的队列。 - 所以在3.x版本中AFN使用了
NSOperationQueue
对网络回调的管理,并且设置maxConcurrentOperationCount
为1,保证了最大的并发数为1,也就是说让网络请求串行执行。避免了多线程环境下的资源抢夺问题。