iOS 10道细节面试题

968 阅读4分钟

最近换工作,已经是有所准备的,但是面试过程中还是很多我觉得比较基础的东西答的不够晚上,怪自己没有深入的思考。下面做个总结:

1. 多线程中NSThread 为什么还存在?

   其实面试官想问的是NSThread、GCD、NSOperation 的区别吧

   答案:

   NSThread

   优点:NSThread 轻量级,使用简单,一个thread 对应一个线程

   缺点:需要自己管理线程的生命周期,线程同步、加锁、睡眠以及唤醒等

   NSOperation

   自带线程管理的抽象类。
   优点:自带线程周期管理,操作上可更注重自己逻辑。更面向对象,可以自定义,kVO监听     状态
   缺点:面向对象的抽象类,只能实现它或者使用它定义好的两个子类

   GCD 

   优点:基于多核的,最高效,避开并发陷阱。
   缺点:基于C实现。多线程优先级,线程取消等问题处理比较麻烦


2. SQLite 多线程问题

在不考虑效率的情况下SQLite 其实有三种方式实现

1.  多个线程公用一个数据库链接(不合适)

原因:多个线程之间的同步太麻烦。

2. 每个线程管理自己的数据库链接(不合适)

原因:线程数过多(上百左右个线程发起数据操作)会导致数据库压力大,尤其是有事务操作时会发起很多事务请求,这时所有的带事务请求都会卡在beginTransaction,严重影响性能

3. 串行队列异步的管理多线程(FMDB)

通过实现一个FMDatabaseQueue单例串行队列,其实是CGD实现的

更多关于SQLlite 优化参考

www.cnblogs.com/huozhong/p/…

3. initialize 自类没有实现的情况下,父类initialize会调用几次?

答案是2次,原因是 

initialize 原理是 ((void(*)(Class, SEL))objc_msgSend)(cls, SEL_initialize) 方式

因为你的子类没有定义 initialize 类方法,所以消息是由父类的 initialize 类方法处理的

还有一个比较常见的考察是和load 方法对比,详细的就不在这儿描述了

blog.csdn.net/fys_0801/ar…

4. 打印[self class] 和 [super class] 为什么一样

由于都没有重写class方法,所以self 和 super都调用的是基类的class方法,所以结果肯定是一样的,然后[self class]必定是当前实例的类对象也就是ClassB;所以[super class]也是一样的结果

那么问题来了?那为什么[super init] 方法却能调用父类的呢?

原因是

super是用来处理运行时消息转发的边界问题;一般的方法调用都回转成运行时c语言方法:objc_msgSend(id self, SEL cmd, ...),然而当遇到super时会调用objc_msgSendSuper来处理消息,也就是去父类的方法表中中找方法

5. 206 状态码是什么意义

这个问题是考察我的http 基本功,可惜基本功太差,没有答上来,惭愧

正确是:客户发送了一个带有Range头的GET请求,服务器完成了它。断点续传的时候用得到

6. JSPatch 当有5个参数的时候如何处理的

其实前面的时候问JSPatch 原理的时候,我答的还是不错的,当问到这个的时候,我就感觉我前面的努力白费了。技不如人认了。

回来特意看了一下源码,就是这样列举的方式。。。


7.关于NSString的retainCount 

NSString 不同的方式,调用retainCount 为什么结果差别那么大

1. 常量的方式

NSString *s = @"test";
NSLog(@"s:%d",[s retainCount]); // -1或2147483647(即UINT_MAX ( Maximum value an `unsigned int')

2. stringWithFormat 方式

NSString *s = [NSString stringWithFormat:@"%s", "test"];
NSLog(@"s:%d",[s retainCount]); // 1
使用stringWithFormat创建的NSString为变量,系统会进行引用计数

3. stringWithString

stringWithString这个方法比较特别:它的retainCount取决于它后面跟的string对象
NSString *s1 = [NSString stringWithString:@"test"];
NSString *s2 = [NSString stringWithString:[NSString stringWithFormat:@"test,%d",1]];
NSLog(@"s1:%d",[s1 retainCount]); // 2147483647
NSLog(@"s2:%d",[s2 retainCount]); // 2

8. performSelector withObject afterDelay

聪明的你们一定是知道,面试官要问为什么这个方法在自线程中调用正常吗?为什么

1、带有afterDelay参数的方式是使用当前线程的定时器在一定时间后调用SEL,而 performSelector withObject 方式是直接调用SEL。

2、子线程中默认是没有定时器的

解决办法

1. 自线程中开启定时器 [[NSRunLoop currentRunLoop] run];  

2. 采用 dispatch_after  方式替换

9. category 属性如何加weak方式

我们都知道category 都用OBJC_ASSOCIATION的方式添加属性,但是并没有weak 方式


我们都知道NSObject 属性可以加weak 属性,那我们就利用它包装一层

具体代码实现参考文章

zhuanlan.zhihu.com/p/33428509

10. 如何判断当前的队列是哪个队列

用到了GCD的一个关键方法 dispatch_queue_get_label

如判断当前队列是否是主队列

#define dispatch_main_async_safe(block)\    
if (strcmp(dispatch_queue_get_label(DISPATCH_CURRENT_QUEUE_LABEL), dispatch_queue_get_label(dispatch_get_main_queue())) == 0) 
{        
    block();  
} 
else 
{        
    dispatch_async(dispatch_get_main_queue(), block);\    
}
#endif