1.请简述视图控制器的生命周期
(1)alloc:创建对象,分配空间
(2)init:初始化对象
(3)loadView:从xib中载入视图
(4)viewDidLoad:载入完成,可以自定义数据和控件
(5)viewWillAppear:视图将要出现在屏幕上之前
(6)viewDidAppear:视图已经出现在屏幕上
(7)viewWillDisappear:视图将要消失
(8)viewDidDisappear:视图已经消失
(9)销毁
2.UITableView有哪些优化方式
(1)提前计算并缓存好高度(布局),因为heightForRowAtIndexPath是调用最频繁的方法;
(2)异步绘制。遇到复杂界面,遇到性能瓶颈时,可能就是突破口。
(3)滑动时按需加载,这个在大量图片展示,网络加载的时候很管用
(4)cell的复用
(5)尽量少使用或者不用透明的图层
(6)用异步加载数据,缓存请求结果
(7)减少subView的数量
(8)异步刷新
(9)提前注册
3.简述iOS中的事件传递机制
点击一个UIView或产生一个触摸事件A,这个触摸事件A会被添加到UIApplication管理的事件队列中(即,首先接收到事件的是UIApplication)。
UIApplication会从事件队列中取出最前面的事件(此处假设为触摸事件A),把事件A传递给应用程序的主窗口(KeyWindow)。
窗口会在视图层次结构中找到一个最合适的视图来处理触摸事件。
事件交由第一响应者对象处理,如果第一响应者不处理,事件被沿着响应链向上传递,交给下一个响应者,直到事件被丢弃。
4.UITableView中有哪些必须要实现的数据源的方法
(1)每组的行数
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section;
(2)每行的cell
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath;
5.简述HTTP协议中GET请求和POST请求的区别
GET和POST的主要区别表现在数据传递上
(1)GET:
①在请求URL后面以‘?’的形式跟上发送给服务器的参数,多个参数之间用‘&’隔开,比如http://www.test.com/login?username=123&pwd=234&type=JSON
②由于浏览器和服务器对URL长度有限制,因此URL后面附带的参数是限制的,通常不能超过1kb
(2)POST:
①发送给服务器的参数全部放在请求体中
②理论上,POST传递的数据量没有限制(具体还得看服务器的处理能力)
(3)选择
①如果要传递大量数据,比如文件上传,只能用POST请求
②GET的安全性比POST要差些,如果包含机密、敏感信息,建议用POST
③如果仅仅是索取数据(数据查询),建议用GET
④如果是增加、修改、删除数据,建议使用POST
6.简述对异步请求的理解
异步请求:通过两个线程调用服务,一个线程发送,一个线程接受,请求行为在后台,不会导致页面假死
7.iOS中那些技术可以实现开辟线程,他们之间的联系和区别是什么?
创建方式:NSThread,NSOperation,GCD。
联系:
三种编程方式都是针对线程操作来讲的,从上到下,抽象度层次是从低到高的,抽象度越高的使用越简单。
区别:
(1)NSThread:
优点:NSThread比其他两个轻量级,使用简单。
缺点:需要自己管理线程的生命周期、线程同步、加锁、睡眠以及唤醒等。线程同步对数据的加锁会有一定的系统开销。
(2)NSOperation:
不需要关心线程管理,数据同步的事情,可以把精力放在自己需要执行的操作上
NSOperation是面向对象的,基于OC语言实现的API。两种默认实现为:NSInvocationOperation和NSBlockOperation。
(3)GCD:
Grand Central Dispatch是由苹果开发的一个多核编程的解决方案。iOS4.0以后才能使用,是替代NSThread,NSOperation的高效和强大的技术。
GCD是基于C语言的API,提供了非常多强大的函数。GCD会自动管理线程的声明周期(创建线程、调度任务、销毁线程)。程序员只需要告诉GCD想要执行什么任务,不需要比那些人和线程管理代码。我们在编写GCD相关代码的时候,面对的是函数,而不是方法。GCD中的函数大多数都以dispatch开头。
8.NSThread中线程的通信方式
(1)线程间通信:
在1个进程中,线程往往不是孤立存在的,多个线程之间需要经常进行通信。
(2)线程间通信的体现:
①1个线程传递数据给另1个线程;
②在1个线程中执行完特定任务后,转到另1个线程继续执行任务。
线程间通信常用方法:
- (void)performSelectorOnMainThread:(SEL)aSelector withObject:(id)arg waitUntilDone:(BOOL)wait;
- (void)performSelector:(SEL)aSelector onThread:(NSThread *)the withObject:(id)arg waitUntilDone:(BOOL)wait;
举例(下载图片):
//在子线程中调用download方法下载图片
[self performSelectorInBackground:@selector(download) withObject:nil]
- (void)download {
//图片下载完成
//回到主线程中设置图片
//第一种方式
//[self performSelectorOnMainThread:@selector(settingImage:) withObject:image waitUntilDone:NO];
//第二种方式
[self.imageView performSelector:@selector(setImage:) onThread:[NSThread mainThread] withObject:image waitUntilDone:NO];
//第三种方式
[self.iconView performSelectorOnMainThread:@selector(setImage:) withObject:image waitUntilDone:NO];
}
9.GCD的线程通信
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^ {
//执行耗时的异步操作
dispatch_async(dispatch_get_main_queue(), ^ {
//回到主线程,执行UI刷新操作
});
});
9.GCD中有哪些创建线程的方式
GCD全程Grand Central Dispatch,可称为大中央调度。实际上GCD是管理着一个线程池,如何创建线程,如何回收线程,以及分配多少个线程,这些都是GCD来控制的。在开发中,程序员是不用操作程序的相关事情,只需要把应该做的操作放到相应的队列里即可。
在GCD中加入了两个非常重要的概念:任务和队列。
(1)任务:即操作,GCD中就是一个Block。任务有两种执行方式:同步执行和异步执行。
同步(sync)和异步(async)的主要区别自傲与会不会阻塞当前线程,直到Block任务执行完毕。
如果是同步操作,它会阻塞当前线程,并等待Block中的任务执行完毕,然后当前线程才会继续往下运行。
如果是异步(async)操作,当前线程会直接往下执行,它不会阻塞当前线程。
(2)队列:用于存放任务。一种有两种队列,串行队列和并行队列。
串行队列中的任务会根据队列的定义FIFO地执行(即一个接一个的先进先出地进行执行)。
并行队列的任务,GCD也会FIFO地取出来,但不同的是,它取出来一个就会放到别的线程,然后再取出来一个又放到另一个线程。
队列与线程管理:
三大队列种类:
(1)主线程的main queue,通过dispatch_get_main_queue获取。
(2)并行队列global dispatch queue,通过dispatch_get_global_queue获取,由系统创建(不需要开发人员去创建)三个不同优先级的dispatch queue。并行队列的执行顺序与其加入队列的顺序相同。
(3)串行队列serial queue一般用于按顺序同步访问,可创建任意数量的串行队列,各个串行队列之间是并发的。一般用dispatch_queue_create来进行创建,非ARC的情况下需要用户手动来释放队列,可能会有人说,既然队列是一种对象,可以创建和释放,那一定会有引用计数器,确实,可以使用函数dispatch_retain和dispatch_release来增加或减少引用计数。
两种提交job的方式:dispatch_async和dispatch_sync,分别是异步执行和同步执行,两者之前的区别在于,前者把任务提交到队列执行不会阻塞,而后者后面的代码块需要等到队列中的任务执行完成后才可以执行
(1)//主线程异步执行
dispatch_async(dispatch_get_main_queue(), ^{......});
(2)//主线程同步执行
dispatch_sync(dispatch_get_main_queue(), ^{......});
10.GCD在哪三种队列和用法
(1)The main queue:与主线程功能相同。实际上,提交至main queue的任务会在主线程中执行。main queue可以调用dispatch_get_main_queue()来获得。因为main queue是与主线程相关的,所以这是一个串行队列。
(2)Global queue:全局队列是并发队列,并由整个进程共享。进程中存在三个全局队列:高、中(默认)、低三个优先级队列。可以调用dispatch_get_global_queue(0,0)函数传入优先级来访问队列。
(3)用户队列:用户队列(GCD并不这样称呼这种队列,但是没有一个特定的名字来形容这种队列,所以我们称其为用户队列)是用函数dispatch_queue_create(,)(①队列名称,②队列的类型:并行队列DISPATCH_QUEUE_CONCURRENT;串行队列DISPATCH_QUEUE_SERIAL)
11.iOS中有哪些技术可以保证线程安全
增加互斥锁:有效防止因多线程抢夺资源造成的安全问题。线程同步,多条线程按顺序地执行任务。互斥锁就是使用了线程同步计数。
atomic加锁。
12.简述AFNetworking的实现原理
AFN,全称AFNetworking,虽然运行效率没有ASI高,但是使用比ASI简单,是对NSURLConnection和NSURLSession分别进行的封装。
AFN内部的RunLoop:
AFN内部开了一条专门用来访问网络请求的线程,在这个开线程的方法中,它把方法和dispatch_once都用static修饰了下,以保证这个方法的安全性以及只开辟一块内存空间,而且保证它的线程不会卡死。在这个方法中它会调用另一个网络请求入口的方法,在这个入口方法中它会创建一个RunLoop,然后添加一个NSMachPort端口,目的是为了让他里面有Source(因为有了Source的RunLoop才能真正跑起来),然后启动RunLoop,通过RunLoop在里面不断地循环,不断地发送消息,让它做事情
13.Block有什么用途
Block是对象,它封装了一段代码,这段代码可以在任何时候执行。
Block可以作为函数参数或者函数的返回值,而其本身又可以携带参数或者返回值。它和传统的函数指针很类似,但是有区别:Block是inline的,并且它对局部变量是只读的。
网友评论