2020卓敦的面试之旅总结-iOS面试题

前言


由于种种原因,我离开了上家公司,加上现在是疫情期间。招人的少,找工作的多。不好好准备一下,真的是竹篮打水一场空。虽然我是初级开发者,但是也要好好学习。离开公司之后,找工作找了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、调用一个方法的时候,这个过程发生了什么事

答:
首先来看看类在runtime中的结构

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

结束


平时得好好学习沉淀自己,通过这次找工作意识到现在公司对开发者的要求是越来越高,不仅仅满足于开发业务代码。不过要记住一句话,宁缺毋滥。总有合适的公司等着你

你可能感兴趣的:(2020卓敦的面试之旅总结-iOS面试题)