一、 GCD和NSOperation的比较
1.GCD是纯C语言的API,NSOperationQueue是基于GCD的OC版本封装
2.GCD仅仅支持FIFO队列,只可以设置队列的优先级,而NSOperationQueue中的每一个任务都可以被重新设置优先级(setQueuePriority:),从而实现不同操作的执行顺序调整
3.GCD不支持异步操作之间的依赖关系设置。如果某个操作的依赖另一个操作的数据,使用NSOperationQueue能够设置依赖按照正确的顺序执行操作(addDependency:)。GCD则没有内建的依赖关系支持(只能通过Barrior和同步任务手动实现)。
4. NSOperationQueue方便停止队列中的任务(cancelAllOperations, suspended),GCD不方便停止队列中的任务.
5. NSOperationQueue支持KVO,可以监测operation是否正在执行(isExecuted)、是否结束(isFinished),是否取消(isCanceld)
6.GCD的执行速度比NSOperationQueue快
7. NSOperationQueue可设置最大并发数量(节电),GCD具有dispatch_once(只执行一次,单例)和dispatch_after(延迟执行)功能
NSThread 一般主要用它来查看线程
二、 Runtime
运行时,它是一种机制
1、它可以动态的创建一个类,比如KVO的实现原理
2、可以动态的修改或创建一个类的属性、方法
3、可以遍历一个类的所有属性和方法
4、可以将动态的生成一个方法,并将原本的方法替换掉,比如AFN发送NSURLSession请求时,我们需要resume,当这个时候,runtime会生成一个方法将这个方法替换掉,并发出通知,使菊花转动,当获取到网络数据的时候在发出通知,取消菊花转动
1> 什么是runtime
runtime是一套比较底层的纯C语言API, 属于1个C语言库, 包含了很多底层的C语言API。
在我们平时编写的OC代码中, 程序运行过程时, 其实最终都是转成了runtime的C语言代码, runtime算是OC的幕后工作者,objc_msgSend
2> runtime干什么用,使用场景
runtime是属于OC的底层, 可以进行一些非常底层的操作(用OC是无法现实的, 不好实现)
在程序运行过程中, 动态创建一个类(比如KVO的底层实现) objc_allocateClassPair,class_addIvar,objc_registerClassPair
在程序运行过程中, 动态地为某个类添加属性\方法, 修改属性值\方法(修改封装的框架) objc_setAssociatedObject object_setIvar
遍历一个类的所有成员变量(属性)\所有方法(字典转模型,归解档) class_copyIvarList class_copyPropertyList class_copyMethodList
三、Runloop
运行循环,运行循环的存在依赖多线程,当我们运行一个进程时,默认会创建一条线程,这个线程就是主线程,主线程的运行循环默认是开启的,子线程的运行循环是关闭的,需要我们输欧东开启,运行循环有两个源 inputSource和 timerSource
inputSource,输入源,是用来与子线程进行交互的
timerSource 定时源,是用来处理主线程操作的,如更新UI等
四、单例
保证程序运行过程中,永远只有一个实例对象
它的目的是:全局共享一份资源,节省不必要的内存开销,同时它能够保证获取到的数据的相同,起到一定的安全性
像我们平时封装的一些工具类都是使用了单例,单例的实现是通过GCD中的一次性代码来完成的(可以接着说GCD,NSOpertion一些多线程的问题)
五、 响应者链条
当触摸事件发生时,压力转为电信号,iOS系统将产生UIEvent对象,记录事件产生的时间和类型,然后系统将事件加入到一个由UIApplication管理的事件队列中。
UIApplication会从事件队列中取出最前面的事件,并将事件分发下去以便处理,通常,先发送事件给应用程序的主窗口(keyWindow)
主窗口会在视图层次结构中找到一个最合适的视图来处理触摸事件(从父到子,从后到前),这也是整个事件处理过程的第一步
找到合适的视图控件后,就会调用视图控件的touches方法来作具体的事件处理六、Json/XML数据解析
Json数据的解析直接通过苹果源生的方法就可解析(序列化、反序列化)
XML解析方式有两种:DOM解析和SAX解析
DOM解析一般在MAC上使用,手机身很少使用,因为它会将要解析的文件一次性加载进内存,这对手机来讲,负担过重,手机我们一般采用SAX解析
它的解析步骤为:
1. 创建一个解析器(parser)
2. 设置解析器代理
3. 开始解析
之后XML的解析就在代理方法中进行,有5步
1. 准备文档
2. 发现开始节点
3. 发现节点内容
4. 发现结束节点
5. 解析结束
这5步中其中2、3、4这三步是重复进行的
七、Sdwebimage实现原理
这是一个重量级的框架,它最终发送网络请求的方式是NSURLConnection它的执行步骤是这样的:
当我们获取一张图片时,它首先会去内存缓存(缓存是通过字典存数据的,key是url地址,value是图片)中取,根据url地址,如果有图片,就取出显示,如果没有会磁盘上找,如果有,则显示,没有就说明这张图片需要下载,首先会设置占位图片,然后根据key值看是否有这个操作在,如果有,说明图片正在下载,如果没有,需要创建操作,当图片下载完成之后,将图片显示出来,并将图片添加到内存缓存中,同时删除操作。
八、数据存储方式
1.属性列表
2.Preference(NSUserDefaults)
3.键值归档(NSKeyedArchiver、NSCoding)
4.SQLite数据库
5.Core Data九、 内存管理
一、oc是如何管理内存的
这个分在ARC和非ARC环境下
在非ARC环境下:
1. 每个对象都有一个引用计数器,当我们使用alloc、copy、new创建一个新对象时,它的引用计数器为一,当引用计数器为0时,这个对象就会被销毁,在销毁前会调用一个dealloc方法,相当于这个对象死之前的“遗言”。
2. 当我们reatain一个对象时,会使该对象的引用计数器加1,使用realease或者autorelease,会使引用计数器减1
3. 我们也可以将对象放在autorealeasepool中来管理内存
在ARC环境下:
编译器会自动生成管理内存的代码,不需要我们在考虑对象什么时候销毁,销毁的时候是否要对其他对象进行release
二、内存管理的原则是什么?
这个也要分在ARC和非ARC环境讨论
当在非ARC环境下:
1、当我们使用alloc、copy、new方法创建了一个新的对象,都必须在最后做一次release或者autorelease
2、 只要调用了retain,都必须在最后做一次release或者autorelease
3、 @property如果使用了retain或者copy,就需要对不再使用的对象做一次release或autorelease
如果在ARC环境下:
编译器会自动生成管理内存的代码。不需要我们关心十、 KVC、KVO
KVC:Key-Value-Coding内部的实现:一个对象在调用setValue的时候,
(1)首先根据方法名找到运行方法的时候所需要的环境参数。
(2)他会从自己isa指针结合环境参数,找到具体的方法实现的接口。
(3)再直接查找得来的具体的方法实现。
KV0:键值监听,当一个类的某个属性第一次被监听时,系统运行过程中会动态的创建一个派生类(通过runtime实现),在这个派生类中会重写基类的set方法,并在该方法中发出通知给监听者,实现监听机制
在使用KVO监听时要注意移除监听,否则程序会崩
另外使用KVO监听,性能不好,因为会运行过程中会动态的创建类。
kvo使用场景
①实现上下拉刷新控件contentoffset
②webview混合排版contentsize
③监听模型属性实时更新UI十一、堆和栈的区别
管理方式:
对于栈来讲,是由编译器自动管理,无需我们手工控制;对于堆来说,释放工作由程序员控制,容易产生memory leak。
申请大小:
栈:在Windows下,栈是向低地址扩展的数据结构,是一块连续的内存的区域。这句话的意思是栈顶的地址和栈的最大容量是系统预先规定好的,在 WINDOWS下,栈的大小是2M(也有的说是1M,总之是一个编译时就确定的常数),如果申请的空间超过栈的剩余空间时,将提示overflow。因此,能从栈获得的空间较小。
堆:堆是向高地址扩展的数据结构,是不连续的内存区域。这是由于系统是用链表来存储的空闲内存地址的,自然是不连续的,而链表的遍历方向是由低地址向高地址。堆的大小受限于计算机系统中有效的虚拟内存。由此可见,堆获得的空间比较灵活,也比较大。
碎片问题:
对于堆来讲,频繁的new/delete势必会造成内存空间的不连续,从而造成大量的碎片,使程序效率降低。对于栈来讲,则不会存在这个问题,因为栈是先进后出的队列,他们是如此的一一对应,以至于永远都不可能有一个内存块从栈中间弹出
分配方式:
堆都是动态分配的,没有静态分配的堆。栈有2种分配方式:静态分配和动态分配。静态分配是编译器完成的,比如局部变量的分配。动态分配由alloca函数进行分配,但是栈的动态分配和堆是不同的,他的动态分配是由编译器进行释放,无需我们手工实现。
分配效率:
栈是机器系统提供的数据结构,计算机会在底层对栈提供支持:分配专门的寄存器存放栈的地址,压栈出栈都有专门的指令执行,这就决定了栈的效率比较高。堆则是C/C++函数库提供的,它的机制是很复杂的。
十二、分类的作用
1.将类的实现分散到多个不同文件或多个不同框架中。
2.创建对私有方法的前向引用。
3.向对象添加非正式协议。
十三、 视图的生命周期
loadView - 默认调用super方法,根据控制器创建方式加载视图,重写后将根据重写方法创建视图
viewDidLoad-视图加载完成
viewWillAppear-UIViewController对象的视图即将加入窗口时调用;
viewDidApper-UIViewController对象的视图已经加入到窗口时调用;
viewWillDisappear-UIViewController对象的视图即将消失、被覆盖或是隐藏时调用;
viewDidDisappear-UIViewController对象的视图已经消失、被覆盖或是隐藏时调用;
viewVillUnload-当内存过低时,需要释放一些不需要使用的视图时,即将释放时调用;
viewDidUnload-当内存过低,释放一些不需要的视图时调用。十四、三次握手
第一次握手:建立连接时,客户端发送syn包(syn=j)到服务器,并进入SYN_SEND状态,等待服务器确认;
第二次握手:服务器收到syn包,必须确认客户的SYN(ack=j+1),同时自己也发送一个SYN包(syn=k),即SYN+ACK包,此时服务器进入SYN_RECV状态;
第三次握手:客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK(ack=k+1),此包发送完毕,客户端和服务器进入ESTABLISHED状态,完成三次握手。完成三次握手,客户端与服务器开始传送数据.
十五、 创建控制器的方式
1.通过代码的方式加载viewController
UIViewController *controller = [[UIViewController alloc] init];
2.通过stroyboard来加载viewController
2.1加载storyboard中箭头指向的viewController
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"Main"bundle:nil]; //加载箭头指向的viewController
CZViewController *controller = [storyboardinstantiateInitialViewController];
2.2 加载storyboard中特定标示的viewController(storyboard可以有多个controller)
UIStoryboard *storyboard = [UIStoryboardstoryboardWithName:@"Main" bundle:nil];
CZViewController *controller = [storyboardinstantiateViewControllerWithIdentifier:@"two"];
3通过xib加载viewController
3.1) 传统方法
3.1.1)创建Xib,并指定xib的files owner为自定义控制器类(为了能连线关联管理IB的内容)
3.1.2)xib中要有内容,且xib中描述的控制器类的view属性要与xib的view控件完成关联(关联方法两种,一种是control+files owner拖线到xib中搭建的指定view控件,另一种是指定xib中的view拖线到@interface)
3.1.3)从xib加载viewController
CZViewController *controller = [[CZViewController alloc]initWithNibName:@"CZOneView" bundle:nil];
3.2)bundle中取出xib内容
CZViewController *vc = [[NSBundle mainBundle]loadNibNamed:@"Two" owner:nil options:nil].lastObject;
十六、创建视图的方式
1.用系统的loadView方法创建控制器的视图
2.如果指定加载某个storyboard文件做控制器的视图,就会加载storyboard里面的描述去创建view
3.如果指定读取某个xib文件做控制器的视图,就根据指定的xib文件去加载创建
4.如果有xib文件名和控制器的类名前缀(也就是去掉controller)的名字一样的 xib文件就会用这个xib文件来创建控件器的视图例:控件器的名为 MJViewController xib文件名为 MJView.xib 如果xib文件名后有一个字不一样就不会去根据它去创建如:MJView8.xib
5.找和控制器同名的xib文件去创建
6.如果以上都没有就创建一个空的控制器的视图;
十七、View和layer的区别
图层不会直接渲染到屏幕上,UIView是iOS系统中界面元素的基础,所有的界面元素都是继承自它。它本身完全是由CoreAnimation来实现的。它真正的绘图部分,是由一个CALayer类来管理。UIView本身更像是一个CALayer的管理器。一个UIView上可以有n个CALayer,每个layer显示一种东西,增强UIView的展现能力。
1.都可以显示屏幕效果
2. 如果需要用户交互就要用UIVIew,其可接收触摸事件(继承UIResponder),而CALayer不能接收触摸事件
3.如果没有用户交互可选用CALayer,因为其所在库较小,占用的资源较少