最近换工作,已经是有所准备的,但是面试过程中还是很多我觉得比较基础的东西答的不够晚上,怪自己没有深入的思考。下面做个总结:
1. 多线程中NSThread 为什么还存在?
其实面试官想问的是NSThread、GCD、NSOperation 的区别吧
答案:
NSThread
优点:NSThread 轻量级,使用简单,一个thread 对应一个线程
缺点:需要自己管理线程的生命周期,线程同步、加锁、睡眠以及唤醒等
NSOperation
自带线程管理的抽象类。
优点:自带线程周期管理,操作上可更注重自己逻辑。更面向对象,可以自定义,kVO监听 状态
缺点:面向对象的抽象类,只能实现它或者使用它定义好的两个子类
GCD
优点:基于多核的,最高效,避开并发陷阱。缺点:基于C实现。多线程优先级,线程取消等问题处理比较麻烦
2. SQLite 多线程问题
在不考虑效率的情况下SQLite 其实有三种方式实现
1. 多个线程公用一个数据库链接(不合适)
原因:多个线程之间的同步太麻烦。
2. 每个线程管理自己的数据库链接(不合适)
原因:线程数过多(上百左右个线程发起数据操作)会导致数据库压力大,尤其是有事务操作时会发起很多事务请求,这时所有的带事务请求都会卡在beginTransaction,严重影响性能
3. 串行队列异步的管理多线程(FMDB)
通过实现一个FMDatabaseQueue单例串行队列,其实是CGD实现的
更多关于SQLlite 优化参考
3. initialize 自类没有实现的情况下,父类initialize会调用几次?
答案是2次,原因是
initialize 原理是 ((void(*)(Class, SEL))objc_msgSend)(cls, SEL_initialize) 方式
还有一个比较常见的考察是和load 方法对比,详细的就不在这儿描述了
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 属性,那我们就利用它包装一层
具体代码实现参考文章
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