前言
由于种种原因,我离开了上家公司,加上现在是疫情期间。招人的少,找工作的多。不好好准备一下,真的是竹篮打水一场空。虽然我是初级开发者,但是也要好好学习。离开公司之后,找工作找了20天,这段时间经历了boss直拒、前程担忧、58不成、失联招聘。很多公司都是挂个名在招聘网,发消息基本不回复或者是几个月才回复。这不,前几天,一家公司打电话叫我面试,但是我是一个半月前投的简历。。。。。。。。。
以下就是我这些天面试了好几家公司遇到的问题,在此记录一下,答案不是详细答案,有需要的可以去详细了解。希望能帮助到大家。有什么不对的地方可以指出来我加以改正
1、UIview和CALayer的区别
答:这道题问的时候,我脑海里第一想到的是UIview具有响应事件、而layer没有,UIView主要是对显示内容的管理,而 CALayer 主要侧重显示内容的绘制。UIview是CALayer的高层实现与封装,两者有种依赖的关系。所以一些简单的控件不需要包裹的,用layer可以提高性能。
2、http和https的区别、对称加密和非对称加密
答:HTTP和HTTPS的区别就算不复习也多多少少知道一点,就是安全性的区别和请求过程的差别。对称和非对称这个对于我们移动端来说很陌生,就是公钥和密钥的知识。对称加密的加密和解密都是用的同一个密钥。而非对称加密会分开公有密钥和私有密钥。
3、swift的泛型简单描述一下
答:现在面试不仅问oc,还会问swift。泛型我开发中有用过,但是直到我复习准备面试的时候,才知道这东西叫泛型,真是惭愧。其实就是不用指定类型,比较灵活的一个东西。
4、swift跟oc的区别,有什么优势劣势
答:基本你的简历有写会swift和oc的,都会被问这个问题。最基本的区别就是oc是动态语言、swift是静态语言。swift类型是安全的,因为在编译的时候会进行一个类型检测。而oc因为有runtime,所以在类型安全方面没有swift好。swift定义变量比oc方便快捷,用let或者var就可以。swift运行更快。swift打包出来的安装包比oc打包的要大等等很多方面的区别。
5、说说几个你常用的第三方库的实现原理
答:我说的是AFN,就是早期对NSURLConnection的封装,后面废弃改用NSURLSession。这里他又问我NSURLSession和NSURLConnection有什么区别。就是前者可以暂停网络请求,而后者只能停止然后重新开始。下载文件的时候,后者是先下载到内存,然后再写入沙盒,如果数据很大,会出现内存暴涨,而NSURLsession是默认下载到沙盒的tem文件夹,不会出现内存暴涨,不过下载完成就会移除,所以需要在回调的时候增加一个保存的代码。
6、runloop的实现原理
答:内部实现其实就是个do while死循环。从我点击APP图标开始,就会开启一个runloop来保证程序的运行。工作的时候运作,没用到的时候休眠。休眠的时候内部会发出一个端口来监听,有事情做的时候端口会发出通知,进而结束休眠进入工作。平时一些优化和解决一些bug也会用到runloop,比如下面有两个问题有说到。
7、delegate为什么用weak,系统有哪些代理是用strong,为什么用strong
答:就是为了防止循环引用。其实不止用weak,有一些也用strong,比如NSURLSession的代理就是用strong,为了防止回调还没完成就被释放了。但是用strong的代理记得在回调完成后及时释放,否则会引起循环引用。
8、kvo怎么监听数组
答:kvo是不能直接监听数组的,需要把数组定义在一个nsobject对象中,通过这个对象来监听才可以。
9、点击屏幕上的按钮,这个过程发生了什么事
答:每次点击屏幕的时候,uikit都会产生一个包含该处理事件的对象,也就是UIevent对象。然后把这个对象放进APP的队列中等待处理。怎么处理,当然得找到点击的这个视图来处理,怎么找。系统会使用触碰测试(hit-testing)来找任何一个在该点击范围内的视图,然后使用递归找子视图,一直找下去,直到没有子视图为止。
10、调用一个方法的时候,这个过程发生了什么事
答:1.在类的缓存方法列表中去找要调用的方法,找到直接执行其实现。
2.如果类的缓存方法列表里没找到,就去meta类的方法列表里找,找到了就执行其实现。
3.还没找到,说明这个类自己没有了,就会通过isa去meta类的父类里执行1、2。
4.如果找到了根meta类还没找到,那么就是没有了,会转向一个拦截调用的方法,可以自己在拦截调用方法里面做一些处理。
5.如果没有在拦截调用里做处理,那么就会报错崩溃
11、nsarray和mutablearray被copy和mutablecopy修饰的结果
答:NSMutableArray被copy修饰之后变成NSArray,这时候进行增删改查会报错
NSMutableArray被mutablecopy修饰之后变成NSMutableArray
NSArray被copy修饰之后还是NSArray,没有产生新对象
NSArray被mutablecopy修饰之后变成NSMutableArray
12、浅拷贝和深拷贝的理解
答:浅拷贝就是拷贝指针,深拷贝就是拷贝地址。
13、简述一下控制器的生命周期
答:无非就是init、load、viewdidload、viewwilldidappear等等的执行顺序
14、oc是怎么进行内存管理的
答:现在的公司项目基本都是ARC了,就是利用引用计数来管理。MRC时代的时候,我还没参加工作,也不怎么懂。
15、简述最常用的属性修饰词、weak、strong、copy等等
答:就是说一下这些属性平时用在什么地方等等。像weak就是修饰代理等等、copy就是修饰block等等。说到这里,他还问了block为什么用copy。因为block定义的时候是在栈,这个是系统自动回收的,我们得把他拷贝到堆上,由我们自己去释放。
16、怎么控制并发
答:我一开始总是把并发和并行搞混。并发是指若干个事件在一个时间间隔内发生,得一件一件来处理。并行是指若干个时间在同一时刻发生,可以同时处理。我项目中并发是用信号量和NSOperationQueue来做
17、gcd的使用
答:面试官想了解你平时开发中是怎么用gcd的,用来解决什么问题,根据你自身情况就行
18、tableview复用机制
答:只有当你所创建的cell数多于屏幕能够显示的数目时才会发生复用机制,就是不用创建所有数量的cell,当cell离开屏幕的时候会放进缓存池,显示出来的时候可以从缓存池取
19、tableviewcell缓存池缓存多少个
答:屏幕最多显示多少个就缓存多少个
20、tableview头部和尾部可以复用
答:组的头部尾部可以,tableview的不可以
21、block有多少种,有什么区别
答:没查资料之前,我一直以为block就一种。其实有三种。堆block、栈block、全局block。我们平时定义的大部分是堆block
22、各种控件的继承类是谁
答:他问了我UIview和UIviewcontroller。UIview的父类和UIviewcontroller的父类都是UIResponder。
23、各设备间字体怎么适配
答:这一个我的做法跟文章的一样(传送门)
24、UItableview和UIcollectionview的区别
答:布局方式不一样、后者对于自定义样式比较灵活、后者有水平和垂直两个滚动方向
25、堆和栈的区别
答:这个问题我当时支支吾吾的说了一些,平时开发中基本不怎么了解这些东西
26、UIview可以在子线程设置frame吗,设置frame算是刷新UI吗
答:不能,刷新UI要在主线程
27、UIview的layoutsubviews触发时机是怎么样的
答:我当时说的是进行布局时执行,用于设置控件的frame
28、oc的switch和swift的switch有什么区别
答:虽然oc和swift的switch都是用来做判断执行,但是还是有区别。oc的switch语句分支必须是整数,而且每个语句需要break。swift的switch语句分支可以是各种类型,而且可以不用break。swift的Switch还能判断string类型
29、说说Swift中数组的map、filter、reduce
答:可以看看这篇文章
30、oc支持多继承吗
答:不可以
31、oc如何实现多继承
答:要是上一道题答可以的话,估计不会往下问了。实现多继承的方式有:1、使用delegate,我个人感觉这个不符合多继承的理念。2、利用组合,就是把对象声明成变量的形式。3、增加分类
32、flutter是多线程还是单线程
答:因为我做过flutter项目,也在简历中写了,所以面试官顺便问了我这个问题。flutter默认是单线程
33、项目中如何配置多域名情况,就是生产环境和测试环境和其他环境各自的域名,除了在pch判断环境来切换,还有啥方法
答:在工程配置config文件
34、gcd和nsoperation有什么区别
答:gcd的核心是c语言,nsoperation可以说是在gcd基础上封装的。nsoperation可以设置优先级,而gcd只能设置队列的优先级。nsoperation可以取消任务。
35、i++和++i的区别
答:前者是先赋值后加,后者是先加后赋值。也就是n=5++,n等于5。n=++5,n等于6。
36、tableview调优策略
答:1、避免开过多线程、cell的图片都是异步加载,每次滑动的时候也是会加载的,这样会增加内存开销,应该设置在滑动停止的时候才开始加载图片。
2、图片过大会造成GPU负荷,可以压缩之后再显示
3、使用Core Graphics实现圆角等功能。
4、使用cell的复用机制
5、缓存cell高度,在数据回调之后计算并保存在model上
6、计算高度时,尽量避免逻辑运算,尽可能使用加减乘除
7、使用drawRect添加子控件
8、尽量少使用xib,因为xib会被编译,也是需要性能消耗的。
9、少使用约束,因为约束会被转换为frame,多了一步
37、tableview如何在滑动停止的时候才开始加载图片
答:面试官会问我这个问题是因为上一个问题我说了这个点,面试官都是喜欢深挖的,一个问题挖下去。这个问题可以把设置图片的操作放在runloop的defaultmode里面,因为在滑动的时候,mode是trackingmode,导致这个设置图片的方法不会被执行,等滑动停止的时候,状态切换回来了,就开始执行了
38、为什么tableview在滑动的时候,cell上的timer会停止
答:那是因为runloop不能同时有两个mode,在滑动的时候,mode是UITrackingRunLoopMode。
与timer的mode不一致,所以会停止,需要把timer的mode改为UITrackingRunLoopMode或者NSRunLoopCommonModes就可以
39、load和initialize的区别,他们的执行时机是怎么样的
答:load:当类被引进项目的时候就会执行该方法,执行时机比main函数还前,不管这个类有没有被用到,并且只会调用一次。一般用于方法交换的时候。
initialize:当项目被初始化的时候,第一个方法被调用之前调用。一般用于初始化静态变量之类的
两者都是线程安全的,因为在内部加了锁,所以使用的时候避免阻塞
40、kvo的实现为什么要新建一个派生类
答:这里我能想到的就是开销的问题,新建派生类继承并重写了属性的setter,这样哈希表里面查找的时间也相对减少,如果不新建的话,可能在哈希表里面查找的时间变长。我的理解是这样,有错误的请指正,多多指教
41、对runtime的理解和平时项目中用到runtime的情况
答:RunTime实际上是一个库,这个库使我们可以在程序运行时动态的创建对象、检查对象,修改类和对象的方法。他的作用其实就是在程序运行时做一些事情。
项目中我用到runtime其实就一个场景,就是给分类添加属性
42、上一问题的延伸,为什么分类不能直接添加属性,需要使用runtime来添加
答:
struct _category_t {
const char *name;
struct _class_t *cls;
const struct _method_list_t *instance_methods; // 对象方法列表
const struct _method_list_t *class_methods; // 类方法列表
const struct _protocol_list_t *protocols; // 协议列表
const struct _prop_list_t *properties; // 属性列表
};
1.从结构体可以知道,有属性列表,所以分类可以声明属性,但是分类只会生成该属性对应的get和set的声明,没有去实现该方法。
2.结构体没有成员变量列表,所以不能声明成员变量。
如何使用runtime添加属性
#import "Student+Extern.h"
#import
static NSString *nameKey = @"nameKey"; //定义一个key值
@implementation Student (Extern)
- (void)setName:(NSString *)name {
objc_setAssociatedObject(self, &nameKey, name, OBJC_ASSOCIATION_COPY);
}
- (NSString *)name {
return objc_getAssociatedObject(self, &nameKey);
}
@end
结束
平时得好好学习沉淀自己,通过这次找工作意识到现在公司对开发者的要求是越来越高,不仅仅满足于开发业务代码。不过要记住一句话,宁缺毋滥。总有合适的公司等着你