https://www.jianshu.com/p/53626346a388
1.TCP协议三次握手
刚开始客户端处于closed状态,服务端处于listen状态
第一次握手:客户端发送syn包(syn=j)到服务器,并进入syn_send状态,等待服务器确认;
第二次握手:服务器收到syn包,必须确认客户端的syn(ack=j+1),同时自己也发送一个syn包(syn=k),即syn+ack包,此时服务器进入syn_recv状态;
第三次握手:客户端收到服务器的syn+ack包,向服务器发送确认包ack(ack=k+1),服务器收到ack包后,客户端和服务器进入established状态,完成3次握手;
作用是为了确认双方的接收和发送能力是否正常。
第一次握手:客户端发送网络包,服务端收到了,服务端就能得出结论:客户端的发送能力、服务端的接收能力正常。
第二次握手:服务端发包,客户端收到了。服务端得出结论:服务端的接收、发送能力正常,客户端的接收、发送能力正常,此时服务端并不能确认客户端的接收能力是否正常
第三次握手:客户端发包,服务端收到了。服务端得出结论:客户端的接收、发送能力正常,服务端的发送、接收能力也正常
三次握手的作用:
1.确认双方的接收能力、发送能力是否正常;
2.指定自己的初始化序列号,为后面的可靠传送做准备;
3.如果是https协议的话,三次握手这个过程,还会进行数字证书的验证以及加密秘钥的生成;
4.https协议在三次握手之后,还有TLS握手
2.TCP协议四次挥手
刚开始双方都处于 establised 状态,假如是客户端先发起关闭请求,则:
第一次挥手:客户端发送一个 FIN 报文,报文中会指定一个序列号。此时客户端处于CLOSED_WAIT1状态。
第二次握手:服务端收到 FIN 之后,会发送 ACK 报文,且把客户端的序列号值 + 1 作为 ACK 报文的序列号值,表明已经收到客户端的报文了,此时服务端处于CLOSE_WAIT2状态。
第三次挥手:如果服务端也想断开连接了,和客户端的第一次挥手一样,发给 FIN 报文,且指定一个序列号。此时服务端处于 LAST_ACK 的状态。
第四次挥手: 客户端收到 FIN 之后,一样发送一个 ACK 报文作为应答,且把服务端的序列号值 + 1 作为自己 ACK 报文的序列号值,此时客户端处于 TIME_WAIT 状态。需要过一阵子以确保服务端收到自己的 ACK 报文之后才会进入 CLOSED 状态
服务端收到 ACK 报文之后,就处于关闭连接了,处于 CLOSED 状态。
简单记忆:对方一个 FIN 报文,我方一个 ACK 报文,再我方一个 FIN 报文,对方一个 ACK 报文,然后结束。
3.iOS内存管理机制
iOS内存管理机制的原理是引用计数,当这块内存被创建后,他的引用计数从0变为1,表示有一个对象或者指针持有这块内存,拥有这块内存的所有权,如果这时候有另外一个对象或者指针指向这块内存,那么为了表示这个后来的对象或者指针对这块内存的所有权,引用计数加1,从1变为2,之后若有一个对象或指针不再指向这块内存时,引用计数减1,表示这个对象或者指针不再拥有这块内存的所有权,当一块内存的引用计数变为0,表示没有任何对象或者指针持有这块内存,系统便会立刻释放掉这块内存。
alloc、new:类初始化方法,开辟新的内存空间,引用计数+1
retain:实例方法,不会开辟新的内存空间,引用计数+1
copy:实例方法,把一个对象复制到新的内存空间,新的内存空间引用计数+1,旧的不会。其中分为浅拷贝和深拷贝,浅拷贝只是拷贝地址,不会开辟新的内存空间;深拷贝是拷贝内容,会开辟新的内存空间
(copy方法:如果是非可扩展类对象,则是浅拷贝。如果是可扩展类对象,则是深拷贝。
mutableCopy方法:无论是可扩展类对象还是不可扩展类对象,都是深拷贝。)
strong:强引用,引用计数+1
release:实例方法,释放对象,引用计数-1
autorelease:延迟释放;autoreleasepool自动释放池;当执行完之后引用计数-1;
initWithFormat和stringWithFormat字符串长度大于9时,引用计数+1;
assign:弱引用,不但能作用于对象还能作用于基本数据类型,但是所指向的对象销毁时不会将当前指向对象的指针指向nil有野指针的生成;
weak:弱引用,只能作用于对象,不能作用于基本数据类型,所指向的对象销毁时会将当前指向对象的指针指向nil,防止野指针的生成;
4.NSThread、GCD、NSOperation多线程
NSThread
NSThread 是封装程度最小最轻量级的,使用更灵活,但要手动管理线程的生命周期、线程同步和线程加锁等,开销较大。
[NSThread isMultiThreaded];//BOOL 是否开启了多线程
[NSThread currentThread];//NSThread 获取当前线程
[NSThread mainThread];//NSThread 获取主线程
[NSThread sleepForTimeInterval:1];//线程睡眠1s
GCD
Grand Central Dispatch(GCD) 是异步执行任务的技术之一。GCD用非常简洁的记述方法,实现了极为复杂的多线程编程。
GCD相关代码:
dispatch_sync:同步操作 dispatch_async:异步操作
dispatch_queue_t:主要有串行和并发两种队列:
dispatch_queue_create("concurrent_queue",DISPATCH_QUEUE_CONCURRENT)并发;
dispatch_queue_create("serial_queue",DISPATCH_QUEUE_SERIAL)串行;
dispatch_once_t;//代码只会被执行一次,用于单例
dispatch_after;//延迟操作
dispatch_get_main_queue;//回到主线程操作
使用GCD的好处
GCD可用于多核的并行运算
GCD会自动利用更多的CPU内核(双核、四核)
GCD会自动管理线程的生命周期(创建线程、调度任务、销毁线程)
程序员只需要告诉GCD想要执行什么任务,不需要编写任何线程管理代码
NSOperation
NSOperation是基于GCD封装的,比GCD可控性更强,可以加入操作依赖(addDependency)、设置操作队列最大可并发执行的操作个数(setMaxConcurrentOperationCount)、取消操作(cancel)等,需要使用两个他的实体子类:NSBlockOperation和NSInvocationOperation,或者继承NSOperation自定义子类;NSBlockOperation和NSInvocationOperation用法的主要区别是:前者执行指定的方法,后者执行代码块,相对来说后者更加灵活易用。NSOperation操作配置完成后便可调用start函数在当前线程执行,如果要异步执行避免阻塞当前线程则可以加入NSOperationQueue中异步执行。
5、Block实现原理;堆上和栈上的数据如何同步?
block本质上也是一个oc对象,他内部也有一个isa指针。block是封装了函数调用以及函数调用环境的OC对象。结构体,在栈上的情况, Block中的指针只是指向栈上的__block变量, 而当Block/__block变量被copy到堆上以后, 堆上Block会持有堆上__block变量. 而堆上的Block再次被调用copy时, 只是Block的引用计数+1而已, 而__block变量如果被多个堆上Block持有也只涉及到引用记数的变化. 一旦Block/__block变量的引用计数为0, 就会自动从堆上释放内存.这里Block/__block变量在堆上的内存管理与Objective-C对象完全一致
6、单例模式
1、何为单例模式?
这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。
单例类只能有一个实例。单例类必须自己创建自己的唯一实例。单例类必须给所有其他对象提供这一实例。
2、如何使用单例模式?
当您想控制实例数目,节省系统资源的时候。
3、单例模式的优缺点
优点:在内存里只有一个实例,减少了内存的开销,尤其是频繁的创建和销毁实例,避免对资源的多重占用比如写文件操作。
缺点:没有接口,不能继承,与单一职责原则冲突,一个类应该只关心内部逻辑,而不关心外面怎么样来实例化。
7、如何删除单链表中一个元素?
先来看看删除的原理:因为数据结构是单链表,要想删除第i个节点,就要找到第i个节点;要想找到第i个节点,就要找到第i-1个节点;要想找到第i-1个节点,就要找到第i-2个节点…于是就要从第一个节点开始找起,一直找到第i-1个节点。如何找?让一个指针从头结点开始移动,一直移动到第i-1个节点为止。这个过程中可以用一个变量j从0开始计数,一直自增到i-1。之后呢?我们把第i-1个节点找到了,就让它的指针域指向第i+1个节点,这样就达到了删除的目的。而第i+1个节点的地址又从第i个节点获得,第i个节点的地址又是第i-1个节点的后继。因此我们可以这样做:先让一个指针指向第i-1个节点的后继,(保存i+1节点的地址),再让i-1节点的后继指向第i个节点的后继,这样就将第i个节点删除了。
8、RunLoop的实现原理
RunLoop实际上是一个对象,这个对象在循环中用来处理程序运行过程中出现的各种事件(比如说触摸事件、UI刷新事件、定时器事件、Selector事件)和消息,从而保持程序的持续运行,而且在没有事件处理的时候,会进入睡眠模式,从而节省CPU资源,提高程序性能。
9、简述Runtime,发送消息的过程
动态的添加对象的成员变量和方法;动态交换两个方法的实现;拦截并替换方法;在方法上增加额外功能;实现NSCoding的自动归档和解档;实现字典转模型的自动转换;
10、离屏渲染
离屏渲染是指图层在被显示之前是在当前屏幕缓冲区以外开辟的一个缓冲区进行渲染操作。
离屏渲染需要多次切换上下文环境:先是从当前屏幕(On-Screen)切换到离屏(Off-Screen);等到离屏渲染结束以后,将离屏缓冲区的渲染结果显示到屏幕上又需要将上下文环境从离屏切换到当前屏幕,而上下文环境的切换是一项高开销的动作。
1.阴影(UIView.layer.shadowOffset/shadowRadius/…)
2.圆角(当 UIView.layer.cornerRadius 和 UIView.layer.maskToBounds 一起使用时)
3.图层蒙板
4.开启光栅化(shouldRasterize = true)
1、使用CAShapeLayer和UIBezierPath设置圆角;
2、UIBezierPath和Core Graphics框架画出一个圆角;
11、KVC
12、KVO
13、iOS内存分区情况
栈区stack
由编译器自动分配释放,存放函数的参数,局部变量的值等
栈是向低地址扩展的数据结构,是一块连续的内存区域