1、栈和堆的区别
管理方式
栈是由编译器自动管理,无需手动释放;
堆得释放是由程序员控制的,容易产生内存泄漏(memory leak)。
申请大小
栈是由高地址往低地址扩展的数据结构,是一块连续的内存区域。即:栈顶的地址和栈的最大容量是系统预先定好的,如果申请的空间超过栈的剩余空间时,将提示溢出溢出(overflow)。因此,能从栈获取的空间较小;
堆时从低地址向高地址扩展的数据结构,是不连续的内存的区域。这是由于系统使用链表存储空闲内存地址的,自然是不连续的,而链表的遍历方向是由低地址向高地址。堆的大小受限于计算机系统中有效的虚拟内存。因此,堆获得的空间比较灵活,也比较大。
碎片问题
对于堆来说,频繁的new、delete,势必会造成存储空间的不连续,从而产生大量的碎片,会降低程序的效率;
对于栈来说,则不会出现这个问题,因为栈是先进后出的队列,一一对应,不可能有一个内存从栈中间弹出。
分配方式
所有的堆都是动态分配的;
栈有静态和动态两种分配方式:静态分配是由编译器完成的,比如局部变量的分配;动态分配由alloc函数进行分配。
特别指出,栈的动态分配,其释放是由编译器自动完成的。
分配效率
栈是机器系统提供的数据结构,计算机会在底层对栈提供支持:分配专门的寄存器存放栈的地址,压栈出栈都有专门的指令执行,这就决定了栈的效率比较高;
堆则是C/C++函数库提供的,机制较为复杂。
2、自动释放池(autoreleasepool)及其工作机制
当向一个对象发送一条autorelease消息时,Cocoa就会将该对象的一个引用放到最新的自动释放池。它仍然是个正常的对象,因此自动释放池定义的作用域内的其他对象可以向它发送消息。当程序执行到作用域结束的位置时,自动释放池会被释放掉,相应的池中的所有的对象也会被释放掉。
(1)obj-c是通过“引用计数”(referring counting)的方式进行内存管理的,对象在分配内存(alloc)的时候,引用计数为1,以后每次碰到copy、retain等的时候,引用计数都会+1,而每次碰到release、autorelease的时候,引用计数就会-1。如果引用计数变为0,就会被销毁;
(2)NSAutoreleasePool就是用来管理引用计数的,一般不需要做额外处理;
(3)autorelease和release只时引用计数-1的时机不同而已,autorelease会在对象真正结束使用的时候才将引用计数-1。
3、copy、assign、retain、strong、weak
copy会在内存里拷贝一份对象,两个指针指向不同的地址。一般用来修饰NSString等有对应可变类型的变量。因为它们哟可能和对应的可行类型(NSMutableString)之间进行赋值操作,为确保对象中的字符串不被修改,应该在设置属性时拷贝一份。而若用strong修饰,如果对象在外部被修改了,会影响属性。
assign用于对基本数据类型进行修饰,不更改引用计数。如果用assign来修饰对象,那么对象释放后,指针的地址还是存在的,也就是说指针并没有设置为nil,即野指针。如果后续分配对象到堆上的某块内存时,正好分到这块地址,程序就会crash。之所以可以修饰基本数据类型,是因为基本的数据类型一般分配在栈上,栈的内存会有系统自动处理,不会造成野指针的现象。
ARC下的strong等同于MRC下的retain,都会把引用计数+1.
weak用于修饰NSObject类型,修饰的对象在释放后,指针的地址会被置为nil,是一种弱引用。在ARC环境下,为避免循环引用,往往会把delegate属性用weak修饰,在MRC环境下,则用assign修饰。
weak和strong的区别是,当一个对象不再有strong类型的指针指向它时,它就会被释放,即使还有weak指针指向它,weak指针也会被清除。
3、CALayer和UIView的区别
二者的最大区别就是layer不会直接渲染到屏幕上。
UIView时iOS系统中界面元素的基础,所有有界面元素都是继承自UIView。view本身完全是由CoreAnimation实现的,它本身的回吐部分,是由一个CALayer类来管理。UIView更像是一个CALayer的管理器,一个view上可以有多个layer,每个layer展示一样东西,增强view的展示能力。
4、浅拷浅和深拷贝
浅拷贝只拷贝指向对象的指针,不拷贝引用对象本身;
深拷贝拷贝引用对象本身。
即:对象A,复制后得到A-copy。对于浅拷贝来说,A和A-copy指向的是同一个内存资源,拷贝的只是一个指针,对象本身资源还是只有一份。如果对A-copy进行了修改,A引用的对象也被同样修改。深拷贝相对好理解,内存中存在了两份独立的对象本身。
浅拷贝好比你和你的影子,你完蛋,影子也完蛋;
深拷贝好比你和你的克隆人,你完蛋,克隆人仍然活着。
附一笔试题:在如下代码中
NSArray *array = @[@[@"a", @"b"], @[@"c", @"d"]];
NSArray *copyArray = [array copy];
NSMutableArray *mCopyArray = [array mutableCopy];
copyArray与mCopyArray的地址是否一样?
mCopyArray和array的地址又是否一样?
改变mCopyArray里面的元素,是否会立刻改变array的内容?
并简述原因。
此题考的即是浅拷贝与深拷贝的问题,NSArray中的copy是浅拷贝,mutableCopy是深拷贝。
5、类工厂方法
类工厂方法的实现是为了向客户提供方便,将分配和初始化合在一个步骤中,返回被创建的对象,并进行自动释放处理。这些方法的形式是+(type)className...(其中className不报喊任何前缀)。工厂方法不但可以将分配和初始化合在一起,还可以为初始化的过程提供对象的分配信息。
类工厂方法的另一个目的是使类(比如NSWorkSpace)提供单例实例。虽然init...方法可以确认一个类在每次程序过程中只存在一个实例,但是他必须分配一个“生的”实例,然后还必须释放该实例。
工厂方法可以避免为可能没有用的对象盲目分配内存。
6、类别(Category)的作用,类别与继承的区别
Category可以在不获悉,不改变原有代码的情况下往里面添加新的方法,只能添加,不能删改。而且,如果Category中的方法与原有方法产生冲突,将覆盖原有的方法,因为Category具有更高的优先级。
类别(Category)主要有三个作用:
(1)将类的实现分散到多个不同文件或框架中;
(2)创建对私有方法的前向引用;
(3)向对象添加非正式协议。
继承可以增加、删除、修改方法,而且可以增加属性。
7、TCP连接的“三次握手”
第一次握手:客户端发送syn包(syn=j)到服务器,并进入SYN_SEND状态,等待服务器确认;
第二次握手:服务器收到syn包,必须确认客户的SYN(ack=j+1),同时自己也发送一个syn包(syn=k),即SYN+ACK包,此时服务器进入SYN_RECV状态;
第三次握手:客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK(ack=k+1),此包发送完毕,客户端和服务器进入ESTABLISHED状态,完成三次握手。
握手过程中传送的包里不包含数据,三次握手完成后,客户端和服务端才正式开始传送数据。理想状态下,TCP连接一旦建立,在通信双方中的任何一方主动关闭连接之前,TCP连接都将一直保持下去。断开连接时,服务器和客户端均可以主动发起断开TCP连接的请求,而断开过程则需要经过“四次握手”。
8、Socket和Http
socket是要完整的TCP、UDP协议的接口,而http是基于socket之上的。
socket是对TCP/IP协议的封装,socket本身并不是协议,而是调用一个接口(API)。通过socket,我们才能使用TCP/IP协议。
http协议是简单对象访问协议,对应于应用层,http协议是基于TCP连接的。
TCP/IP是传输层协议,主要解决数据如何在网络中传输。而http是应用层协议,主要解决如何包装数据。
http连接:http连接就是所谓的短连接,即客户端向服务端发送一次请求,服务端响应后,连接就会断掉。
socket连接:socket连接就是所谓的长连接,理论上客户端和服务端一旦建立起连接将不会主动断掉。但是由于各种因素,可能会导致连接断开。当一个socket连接中没有数据的传输,那么为了维持连接,需要发送心跳信息,具体心跳信息的格式是由开发者自定义的。
9、TCP与UDP
TCP(Transmission Control Protocol,传输控制协议)是基于连接的协议,当客户和服务器进行数据交换之前,必须现在双方之间建立一个TCP连接,之后才能传输数据。TCP提供超时重发,丢弃重复数据,检验数据,流量控制等功能,保证数据能从一端传递到另一端。
TCP的连接必须要经历三次“对话”,才能建立起来:
(1)主机A向主机B发出连接请求数据包;
(2)主机B向主机A发送同意连接和要求同步(同步:两台主机一个在发送,一个在接收,协调工作)的数据包;
(3)主机A再发一个数据包确认主机B的要求同步(“我现在要发了,接着吧”)。
三次“对话”的目的是使数据包的发送和接收同步,经过三次“对话”之后,主机A才向主机B正式发送数据。
UDP(User Data Protocol,用户数据协议)是与TCP相对应的协议。UDP是面向非链接的协议,它不与对方建立连接,而是直接把数据包发送过去。UDP适用于一次之传输少量数据,对可靠性要求不高的应用环境。
TCP与UDP区别的几个点:是否面向连接;传输是否可靠;应用于传输数据量;快慢。
10、指针和地址的区别
指针以为着已经有一个指针变量存在,它的值是一个地址。指针变量本身也存放在一个长度为4个字节的地址当中。而地址概念本身并不代表有任何变量存在。
11、关于懒加载(Lazy Loading)
用到的时候再去初始化,也可以理解为延时加载。
例如tableview中的图片加载显示:延时加载,避免内存过高;异步加载,避免线程堵塞。
12、iOS的设计模式中,代理模式和观察者模式分别指的是什么?
13、ARC中的强引用与弱引用的区别
强引用(__strong)持有对象,所以也可以释放对象;
弱引用(__weak)不持有对象,当然也不能释放对象。