iOS面试总结(2022)

自我介绍

面试官好,我叫强行天下,14年毕业于江苏理工学院,8年左右的iOS移动开发经验,13-15年就职于一家电商公司联城数据,任职安卓工程师,参与城与城APP的开发(一款社交电商类的项目)15-16年就职于方寸科技,是一家软件开发公司,任职iOS开发,开始从0-1负责苹果端的项目,主要负责了一款电商项目,16-至今就职于一家金融软件公司(完成2款行业内标准产品研发)主要从事金融方面软件开发,目前任职公司国内业务移动产品线iOS开发组组长,主要负责产品需求对接,项目架构搭建,核心功能开发,包括混合开发技术实施,H5、小程序等开发工作。

内存管理-属性修饰词

读写(readonly,readwrite)

原子性(atomic,noatomic)仅保证获取和赋值要相当线程安全的(set,get方法),但不保证属性的其他操作,如数组的增加或删除操作。

assign用于对基本数据类型进行赋值操作,不更改引用计数。如果用来修饰对象(对象释放的时候,指针仍指向原内存地址,再访问会造成野指针)

weak修饰Object类型对象,修饰的对象在释放后,指针地址会被置为nil,是一种弱引用。

strong是强引用类型,引用计数器随着被引用次数+1,为0的时候释放。

weak当不再有强引用类型的指针指向它的时候,它就会被释放,包含所有弱引用指针也会被清除。

Weak实现原理

在 dealloc 方法内部中,内部具体实现,

扫描二维码关注公众号,回复: 15899315 查看本文章

系统基于runtime对引用对象会维护一张弱引用weak表,通过hash算法,找被废弃对象在弱引用表中的位置,找到弱引用指针的列表数组,进行遍历,将所有弱引用指针变为nil

Block

三种block类型,主要是判断是否引用了外部变量并且是否有copy操作,数据存储位置

不使用外部变量叫全局block

使用外部变量并且未进行copy操作的block是栈block

对栈block进行copy操作,就是堆block,而对全局block进行copy,仍是全局block

内存泄漏(循环引用)NSTimer、block

block中通过__weak可以打破循环引用,NSTimer通过封装一个管理类来避免循环引用

block用copy修饰-为了在block内部引用外部变量,将block默认从栈区复制到堆区

代理用weak修饰-为了避免循环引用

单例,代理,通知,KVCKVOBlock

单例:整体进程过程中,只有一个实例对象,共享一份对象资源,内存空间方面只分配一次。

代理:代理一般用于一对一的消息传递,区别于通知的一对多的传递模式。代理即委托方的方法通过协议让代理方完成具体实现,并且代理完成具体实现可以将返回值返回给委托方。在委托方通过weak声明代理,主要是规避循环引用。

通知:基于观察者模式多用于跨层的消息传递一种机制,传递方法可以一对多的形式。

KVO:是基于观察都模式的另一种实现,系统通过isa混写技术实现,系统在addObserver的同时,基于runtime会基于原对象为父类,动态创建一个kvo_obj的子类,子类重写了父类的setValue的方法,并且原类的isa指针指向了新的子类,内部会调用willChangeValueForKey,didChangeValueForKey,调用到回调方法,完成观察过程。

KVC:系统提供的一种通过变量的值的名称,通过valueForKey和SetValueForKey方法来获取或设置变量值的方法。

首先通过key的访问的实例变量是否有同名的get方法,如果存在完成调用,如果不存在,继续查询同名成员变量,如果还不存在,继续查询父类,如果都不存在会返回unfinded的异常方法。

分类(Category

分类的实现是系统在运行时决定的,分类可以为系统类添加分类,可以添加实例方法,添加属性等,(不能在分类的声明或实现的时候添加成员变量,可以通过runtime的关联对象的方法添加成员变量)

分类添加的方法如果和原类重名,在执行上是覆盖原类方法,多个同名分类方法生效顺序取决于编译顺序。

扩展(Extension

扩展的实现是系统在编译阶段已经决定了,扩展可以用来声明私有属性,声明私有方法,扩展只是以声明的形式存在,具体的实现还是需要在原类中。

多线程

thread要手动管理线程生命周期,使用不多,多使用在长驻线程中

GCD首先底层是C的接口,Operation是基于GCD的一层封装

GCD使用起来简单高效,如果只是加快现有方法的运行速度,选择轻量化的操作使用GCD就更加方便,使用最多。

Operation队列支持KVO,可以检测线程是否正在执行,是否结束(isFinisn),是否取消(isCancel),可以控制队列并发量,一是重新了start方法,需要自行控制所有状态

GCD的执行速度上要比Operation快一点

GCDABC执行完执行D

Dispatch_queue_t,concurrent并发队列,serial串行队列

通过dispatch_group执行完前面请求,最后调用dispatch_group_notify 函数可以返回主队列或其他队列

GCD(多读单写)

主要是写,读的时候通过dispatch_async,写的时候通过dispatch_barrier

线程锁

NSLock

递归锁(NSRecursiveLock)可解决同一个队列多次lock的死锁

synchronized关键词,一般在创建单列的时候使用

GCD中“信号量”

死锁:

死锁就是队列引起了循环等待,无法继续执行

简单例子:主线程中运用主队列同步

同步任务必须要等当前队列执行完,而当前任务与当前方法都在主线程上,队列先进先出的原则,又必须要等当前方法执行完,进而形成了相互循环等待,就造成了死锁

Runloop

线程常驻机制,内部是一个无限循环,确实线程任务能够接受任务消息,并且没有任务的时候能够处理休眠状态

实现线程常驻

为线程创建runloop,向runloop添加source源,并且执行runloop

Runloop常用模式有默认

(Default)模式,默认模式

(tracking)模式,界面跟踪模式

(common)模式,一种伪模式,同步source等到多个model的一种技术

runlopp只能运行在一种模式下,多种模式要进行切换,必须 要暂停当前模式,运行另一种模式

Runtime

系统的方法调用-消息机制:对象根据方法编号SEL去映射表查找对应的方法实现

1、动态交换两个方法的实现

2、动态添加属性

3、动态添加方法

4、拦截并替换方法

5、实现字典与模型的自动转换

性能优化

CPUGPU角度

避免主线程过程的计算与绘制,复杂的多用多线程

减少透明的视图,尽量避免离屏渲染

UI层面

图像的处理:异步请求,本地缓存,按需请求

列表的处理:Cell的重用,数据的异步处理,图片按需加载(离屏渲染),避免滑动过程中加载,复杂图像异步绘制,避免刷新整个列表

通过Xcode提供的Instruments工具提进行检测:

1.Time Profiler:CPU分析工具分析代码的执行时间。

2.Leaks:内存检测,内存泄漏检测工具。

3.Core Animation:图形动态的耗时检测。

离屏渲染

离屏渲染是指除了当前屏幕之外的缓存区之外再开辟另一个缓存区,用来做离屏渲染,便于GPU在规定时间能够从缓存区中提取到数据显示到屏幕上,平时要注意避免离屏渲染,因为它会消耗CPU性能,但是如果在需要CPU配合GPU做一些渲染配合的时候也可以手动开启离屏渲染来达到界面的流畅

第三方库

OC:Sdwebimage,AFNetworking,YYKit。。。

Swift:Kingfisher,Alamofir,SnapKit。。。

其他

svn、git、Cocoapods、组件化、中间件等

加分项:

Android,Vue,uni-app,React,Taro,小程序,Flutter,RN,Java

猜你喜欢

转载自blog.csdn.net/u012378566/article/details/122497330