iOS面试

发布时间 2023-04-11 09:49:17作者: 灵笑若然
1、你使用过Objective-C的运行时编程(Runtime Programming)么?

如果使用过,你用它做了什么?你还能记得你所使用的相关的头文件或者某些方法的名称吗?  

Objecitve-C的重要特性是Runtime(运行时),在#import <objc/runtime.h> 下能看到相关的方法,用过objc_getClass()和class_copyMethodList()获取过私有API;使用  

[java] view plaincopy在CODE上查看代码片派生到我的代码片
 
  1. ```objective-c  
  2. Method method1 = class_getInstanceMethod(cls, sel1);  
  3. Method method2 = class_getInstanceMethod(cls, sel2);  
  4. method_exchangeImplementations(method1, method2);    
  5. ```     

代码交换两个方法,在写unit test时使用到。  

2、CG框架的联系是什么?分别用CA和CG做过些什么动画或者图像上的内容。(有需要的话还可以涉及Quartz的一些内容)  

UI框架的底层有CoreAnimation,CoreAnimation的底层有CoreGraphics。    

[java] view plaincopy在CODE上查看代码片派生到我的代码片
 
  1. UIKit |   
  2. ------------ |   
  3. Core Animation |   
  4. Core Graphics |  
  5. Graphics Hardware|      
3、是否使用过CoreText或者CoreImage等?

如果使用过,请谈谈你使用CoreText或者CoreImage的体验。

CoreText可以解决复杂文字内容排版问题。CoreImage可以处理图片,为其添加各种效果。体验是很强大,挺复杂的。

4、 NSNotification和KVO的区别和用法是什么?什么时候应该使用通知,什么时候应该使用KVO,它们的实现上有什么区别吗?如果用protocol和delegate(或者delegate的Array)来实现类似的功能可能吗?如果可能,会有什么潜在的问题?如果不能,为什么?(虽然protocol和delegate这种东西面试已经面烂了…)

NSNotification是通知模式在iOS的实现,KVO的全称是键值观察(Key-value observing),其是基于KVC(key-value coding)的,KVC是一个通过属性名访问属性变量的机制。例如将Module层的变化,通知到多个Controller对象时,可以使用NSNotification;如果是只需要观察某个对象的某个属性,可以使用KVO。
对于委托模式,在设计模式中是对象适配器模式,其是delegate是指向某个对象的,这是一对一的关系,而在通知模式中,往往是一对多的关系。委托模式,从技术上可以现在改变delegate指向的对象,但不建议这样做,会让人迷惑,如果一个delegate对象不断改变,指向不同的对象。  

5、 你用过NSOperationQueue么?如果用过或者了解的话,你为什么要使用NSOperationQueue,实现了什么?请描述它和GCD的区别和类似的地方(提示:可以从两者的实现机制和适用范围来描述)。

使用NSOperationQueue用来管理子类化的NSOperation对象,控制其线程并发数目。GCD和NSOperation都可以实现对线程的管理,区别是 NSOperation和NSOperationQueue是多线程的面向对象抽象。项目中使用NSOperation的优点是NSOperation是对线程的高度抽象,在项目中使用它,会使项目的程序结构更好,子类化NSOperation的设计思路,是具有面向对象的优点(复用、封装),使得实现是多线程支持,而接口简单,建议在复杂项目中使用。

项目中使用GCD的优点是GCD本身非常简单、易用,对于不复杂的多线程操作,会节省代码量,而Block参数的使用,会是代码更为易读,建议在简单项目中使用。

6、既然提到GCD,那么问一下在使用GCD以及block时要注意些什么?它们两是一回事儿么?block在ARC中和传统的MRC中的行为和用法有没有什么区别,需要注意些什么?

使用block是要注意,若将block做函数参数时,需要把它放到最后,GCD是Grand Central Dispatch,是一个对线程开源类库,而Block是闭包,是能够读取其他函数内部变量的函数。

7、您是否做过异步的网络处理和通讯方面的工作?如果有,能具体介绍一些实现策略么?

使用NSOperation发送异步网络请求,使用NSOperationQueue管理线程数目及优先级,底层是用NSURLConnetion,详细可见开源框架[LWConnetion](https://github.com/xunyn/LWConnetionDemo)。  

8、对于Objective-C,你认为它最大的优点和最大的不足是什么?对于不足之处,现在有没有可用的方法绕过这些不足来实现需求。如果可以的话,你有没有考虑或者实践过重新实现OC的一些功能,如果有,具体会如何做?

最大的优点是它的运行时特性,不足是没有命名空间,对于命名冲突,可以使用长命名法或特殊前缀解决,如果是引入的第三方库之间的命名冲突,可以使用link命令及flag解决冲突。  

9、简单描述开发中使用的框架? 

 Core Data , Core Graphics, Core Animation,和OpenGLES框架 Foundation、UIKit   

10、是否可以在一个视图控制器中嵌入两个tableview控制器? 

一个视图控制只提供了一个View视图,理论上一个  tableViewController也不能放吧, 只能说可以嵌入一个tableview视图。当然,题目本身也有歧义,如果不是我们定性

思维认为的UIViewController, 而是宏观的表示视图控制者,那我们倒是可以把其看成一个视图控制者,它可以控制多个视图控制器,比如TabbarController 那样的感觉。   

11、一个tableView是否可以关联两个不同的数据源?你会怎么处理?  

首先我们从代码来看,数据源如何关联上的,其实是在数据源关联的代理方法里实现的。 因此我们并不关心如何去关联他,他怎么关联上,方法只是让我返回根据自己的需要去设置如相关的数据源。 因此,我觉得可以设置多个数据源啊,但是有个问题是,你这是想干嘛呢?想让列表如何显示,不同的数据源分区块显示?  

12、tableView的重用机制?  

UITableView通过重用单元格来达到节省内存的目的:通过为每个单元格指定一个重用标识符(reuseIdentifier),即指定了单元格的种类,以及当单元格滚出屏幕时,允许恢复单元格以便重用.对于不同种类的单元格使用不同的ID,对于简单的表格,一个标识符就够了.  假如一个TableView中有10个单元格,但是屏幕上最多能显示4个,那么实际上iPhone只是为其分配了4个单元格的内存,没有分配10个,当滚动单元格时,屏幕内显示的单元格重复使用这4个内存   

13、 viewcontroller的一些方法的说明viewDidLoad, viewWillDisappear, viewWillAppear方法的 顺序和 作用? 

viewDidLoad:在视图加载后被调用   viewWillAppear:视图即将可见时调用。默认情况下不执行任何操作 

viewDidAppear: 视图已完全过渡到屏幕上时调用  viewWillDisappear:视图被驳回时调用,覆盖或以其他方式隐藏。默认情况下不执行任何操作  viewDidDisappear:视图被驳回后调用,覆盖或以其他方式隐藏。默认情况下不执行任何操作  先执行viewDidLoad再执行viewWillAppear。    

14、如何实现延迟加载图片?以及加载图片出现的超时问题? 

经常我们会用tableView显示很多条目, 有时候需要显示图片, 但是一次从服务器上取来所有图片对用户来浪费流量, 对服务器也是负担.最好是按需加载,即当该用户要浏览该条目时再去加载它的图片。  重写如下方法 

[java] view plaincopy在CODE上查看代码片派生到我的代码片
 
  1. - (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRow AtIndexPath:(NSIndexPath *)indexPath     
  2.       
  3.     UIImage *image = [self getImageForCellAtIndexPath:indexPath];  //从网上取得图片     
  4.    [cell.imageView setImage:image];     
  5. }    


这虽然解决了延时加载的问题, 但当网速很慢, 或者图片很大时(假设,虽然一般cell中的图很小),你会发现程序可能会失去对用户的响应. 
原因是  

[java] view plaincopy在CODE上查看代码片派生到我的代码片
 
  1. UIImage *image = [self getImageForCellAtIndexPath:indexPath];      


这个方法可能要花费大量的时间,主线程要处理这个method. 所以失去了对用户的响应. 所以要将该方法提出来:  

[java] view plaincopy在CODE上查看代码片派生到我的代码片
 
  1. - (void)updateImageForCellAtIndexPath:(NSIndexPath *)indexPath     
  2. {      
  3.    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];     
  4.     UIImage *image = [self getImageForCellAtIndexPath:indexPath];      
  5.     UITableViewCell *cell = [self.tableView cellForRowAtIndexPath:indexPath];      
  6.     [cell.imageView performSelectorOnMainThread:@selector(setImage:) withObject:image wai tUntilDone:NO];     
  7.     [pool release];     
  8. }     


然后再新开一个线程去做这件事情  

[java] view plaincopy在CODE上查看代码片派生到我的代码片
 
  1. - (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRow AtIndexPath:(NSIndexPath *)indexPath     
  2. {      
  3.    [NSThread detachNewThreadSelector:@selector(updateImageForCellAtIndexPath:) toTarget: self withObject:indexPath];     
  4. }    

同理当我们需要长时间的计算时,也要新开一个线程 去做这个计算以避免程序处于假死状态  以上代码只是示例, 还可以改进的更多, 比如从网上down下来一次后就将图片缓存起来,再次显示的时候就不用去下载。    

14、Object-c的类可以多重继承么?可以实现多个接口么?重写一个类的方式用继承好还是分类好?为什么? 

Objective-c只支持单继承,如果要实现多继承的话,可以通过类别和协议的方式来实现,cocoa 中所有的类都是NSObject 的子类,多继承在这里是用protocol 委托代理 来实现的。  

15、简单描述一下ios的内存管理机制?有没有垃圾回收机制?与java有什么区别? 

 Objective-C的对象在使用完成之后不会自动销毁,需要执行dealloc来释放空间(销毁),否则内存泄露。谁创建,谁释放(类似于“谁污染,谁治理”)。如果你通过alloc、new或copy来创建一个对象,那么你必须调用release或autorelease。换句话说,不是你创建的,就不用你去释放。   

16、 简单描述一下多线程,以及如何处理ios多线程开发?什么情况下会使用多线程?优点?  

存放NSOperation的集合类。 操作和操作队列,基本可以看成java中的线程和线程池的概念。用于处理ios多线程开发的问题。 网上部分资料提到一点是,虽然是queue,但是却并不是带有队列的概念,放入的操作并非是按照严格的先进现出。 这边又有个疑点是,对于队列来说,先进先出的概念是Afunc添加进队列,Bfunc紧跟着也进入队列,Afunc先执行这个是必然的, 但是Bfunc是等Afunc完全操作完以后,B才开始启动并且执行,因此队列的概念离乱上有点违背了多线程处理这个概念。 但是转念一想其实可以参考银行的取票和叫号系统。 因此对于A比B先排队取票但是B率先执行完操作,我们亦然可以感性认为这还是一个队列。 但是后来看到一票关于这操作队列话题的文章,其中有一句提到 “因为两个操作提交的时间间隔很近,线程池中的线程,谁先启动是不定的。” 瞬间觉得这个queue名字有点忽悠人了,还不如pool~ 综合一点,我们知道他可以比较大的用处在于可以帮组多线程编程就好了。   

17、asihttp代码原理,异步请求的原理,异步请求最大数目,为什么只能这么多? 

ASIHTTPRequest是一个简易使用的类库,通过包装CFNetwork API 来简化 和服务器端的通讯. 它编写的语言是Objective-C 能够应用于Mac OS X and iPhone 平台的应用程序.   异步: 请求通过事件触发->服务器处理(这是浏览器仍然可以作其他事情)->处理完毕   这个数量是跟cpu有关的,并发性取决于cpu核数,每个核只能同时处理一个任务.4核cpu理论上可以并发处理4个任务,如果按http来算就是4个请求,但是cpu是抢占式资源,所以一般来说并发量是要根据任务的耗时和cpu的繁忙度来计算4个左右只是个经验值你开10个短耗时的任务和几个长耗时任务的效率是不同的。   

18、 什么是懒汉模式(懒加载)?什么时候使用?好处是什么?  

懒汉模式,只在用到的时候才去初始化。 也可以理解成延时加载。 我觉得最好也最简单的一个列子就是tableView中图片的加载显示了。 一个延时载,避免内存过高,一个异步加载,避免线程堵塞。   

19、ios平台怎么做数据的持久化?coredata和sqlited 的联系?coredata是一个关系型数据库吗?

 iOS中可以有四种持久化数据的方式: 属性列表、对象归档、SQLite3和Core Data;core data可以使你以图形界面的方式快速的定义app的数据模型,同时在你的代码中容易获取到它。core data提供了基础结构去处理常用的功能,例如保存,恢复,撤销和重做,允许你在app中继续创建新的任务。在使用core data的时候,你不用安装额外的数据库系统,因为core data使用内置的sqlite数据库。core data将你app的模型层放入到一组定义在内存中的数据对象。core data会追踪这些对象的改变,同时可以根据需要做相反的改变,例如用户执行撤销命令。当core data在对你app数据的改变进行保存的时候,core data会把这些数据归档,并永久性保存。   mac os x中sqlite库,它是一个轻量级功能强大的关系数据引擎,也很容易嵌入到应用程序。可以在多个平台使用,sqlite是一个轻量级的嵌入式sql数据库编程。与core data框架不同的是,sqlite是使用程序式的,sql的主要的API来直接操作数据表。   

20、什么是PUSH(推送消息)? 在什么情况下使用,使用过哪些推送?百度云推送? 

第 一阶段:BeejiveIM服务器把要发送的消息、目的iPhone的标识打包,发 给APNS。    

第二阶段:APNS在自身的已注册Push服务 的iPhone列表中,查找有相应标识的iPhone,并把消息发到iPhone。   

第三阶段:iPhone把发来的消息传递给相应的应用程序, 并且按照设定弹出Push通知。