iOS开发面试中需要牢牢记住的几个知识点
如何分析dSYM?
dSYM是什么?
Xcode
编译项目之后,我们会看到一个同名的dSYM
文件,dSYM
是保存十六进制函数地址映射信息
的中转文件,我们调试的symbols
都会包含在这个文件中,并且每次编译项目的时候都会生成一个新的dSYM
文件,位于/User/<用户名>/Library/Developer/Xcode/Archives
目录下,对于每一个发布版本我们都很有必要保存对应的Archives
文件;
dSYM文件有什么用?
当我们软件release
模式打包或上线后,不会像我们在Xcode
中那样直观的看到用崩溃的错误,这个时候我们就需要分析crash report
文件了,iOS设备中会有日志文件保存我们每个应用出错的函数内存地址,通过Xcode
的Organizer
可以将iOS设备中的DeviceLog
出成crash文件,这个时候我们就可以通过出错的函数地址
去查询dSYM
文件中程序对应的函数名和文件名。大前提是我们需要有软件版本对应的dSYM
文件,这也是为什么我们很有必要保存每个发布版本的Archives
文件了。
如何将文件一一对应?
每一个xx.app
和xx.app.dSYM
文件都有对应的UUID
, crash
文件也有自己的UUID
,只要这三个文件的UUID
一致,我们就可以通过他们解析出正确的错误函数信息了。
-
1.查看
xx.app
文件的UUID
,terminal
中输入命令:dwarfdump --uuid xx.app/xx
(xx代表你的项目名) -
2.查看
xx.app.dSYM
文件的UUID
,在terminal
中输入命令:dwarfdump --uuid xx.app.dSYM
-
3.
crash
文件内第一行Incident Identifier
就是该crash
文件的UUID
。
关于多线程
多线程分类
- pthread
- 一套通用的多线程API
- 适用于Unix\Linux\Windows等系统
- 跨平台,可移植
- 使用难度大
- 使用语言:C语言
- 使用频率:几乎不使用
- 线程生命周期:开发者进行管理
- NSThread
- 面向对象
- 简单易用,可直接操作线程
- 使用语言:OC语言
- 使用频率:偶尔使用
- 线程生命周期:开发者进行管理
-
GCD
- 替换NSThread的技术
- 充分利用了设备的多核(自动)
- 使用语言:C语言
- 使用频率:经常使用
- 线程生命周期:自动管理
- NSOperation
- 基于GCD
- 比GCD多了一些更简单实用的功能
- 使用更加面向对象
- 使用语言:OC语言
- 使用频率:经常使用
- 线程生命周期:自动管理
如果你正在跳槽或者正准备跳槽不妨动动小手,添加一下咱们的交流群1012951431来获取一份详细的大厂面试资料为你的跳槽多添一份保障。
多线程的原理
同一时间,CPU
只能处理1
条线程,只有1
条线程在工作(执行)多线程并发(同时)执行,其实是CPU
快速地在多条线程之间调度
(切换)如果CPU调度线程的时间足够快,就造成了多线程并发
执行的假象思考:如果线程非常非常多,会发生什么情况?CPU
会在N
多线程之间调度,CPU
会累死,消耗大量的CPU
资源每条线程被调度执行的频次会降低(线程的执行效率降低)
多线程的优点
能适当提高程序的执行效率能适当提高资源利用率(CPU、内存利用率)
多线程的缺点
线程需要占用一定的内存空间(默认情况下,主线程占用1M,子线程占用512KB),如果开启大量的线程,会占用大量的内存空间,降低程序的性能线程越多,CPU在调度线程上的开销就越大程序设计更加复杂:比如线程之间的通信、多线程的数据共享;
GCD与NSOperation的比较
-
1、
GCD
是底层的C语言构成的API,而NSOperationQueue
及相关对象是Objc
的对象。在GCD
中,在队列中执行的是由block
构成的任务,这是一个轻量级的数据结构;而Operation
作为一个对象,为我们提供了更多的选择; -
2、在
NSOperationQueue
中,我们可以随时取消已经设定要准备执行的任务(当然,已经开始的任务就无法阻止了),而GCD
没法停止已经加入queue
的block
(其实是有的,但需要许多复杂的代码); -
3、
NSOperation
能够方便地设置依赖关系,我们可以让一个Operation
依赖于另一个Operation
,这样的话尽管两个Operation
处于同-个并行队列中,但前者会直到后者执行完毕后再执行; -
4、我们能将
KVO
应用在NSOperation
中,可以监听一个Operation
是否完成或取消,这样子能比GCD
更加有效地掌控我们执行的后台任务; -
5、在
NSOperation
中,我们能够设置NSOperation
的priority
优先级,能够使同一个并行队列中的任务区分先后地执行,而在GCD
中,我们只能区分不同任务队列的优先级,如果要区分block
任务的优先级,也需要大量的复杂代码; -
6、我们能够对
NSOperation
进行继承,在这之,上添加成员变量与成员方法,提高整个代码的复用度,这比简单地将block
任务排入执行队列更有自由度,能够在其之.上添加更多自定制的功能。总的来说,Operation queue
提供了更多你在编写多线程程序时需要的功能,并隐藏了许多线程调度,线程取消与线程优先级的复杂代码,为我们提供简单的API
入口。从编程原则来说,一般我们需要尽可能的使用高等级、封装完美的API
,在必须时才使用底层API。但是我认为当我们的需求能够以更简单的底层代码完成的时候,简洁的GCD
或许是个更好的选择,而Operation queue
为我们提供能更多的选择。 -
7、
NSOperation
拥有更多的函数可用,具体查看api。NSOperationQueue
是在GCD
基础.上实现的,只不过是GCD
更高一层的抽象 -
8、在
NSOperationQueue
中,可以建立各个NSOperation
之间的依赖关系。 -
9、
NSOperationQueue
支持KVO
。可以监测operation
是否正在执行(isExecuted
)、是否结束(isFinished
) , 是否取消(isCanceld
) -
10、
GCD
只支持FIFO
的队列,而NSOperationQueue
可以调整队列的执行顺序(通过调整权重)。NSOperationQueue
可以方便的管理并发、NSOperation
之间的优先级。
总结
- 使用
NSOperation
的情况:各个操作之间有依赖关系、操作需要取消暂停、并发管理、控制操作之间优先级,限制同时能执行的线程数量.让线程在某时刻停止/继续等。 - 使用
GCD
的情况:一般的需求很简单的多线程操作,用GCD
都可以了,简单高效。从编程原则来说,一般我们需要尽可能的使用高等级、封装完美的API,在必须时才使用底层API。当需求简单,简洁的GCD
或许是个更好的选择,而Operation queue
为我们提供能更多的选择。
如果你正在跳槽或者正准备跳槽不妨动动小手,添加一下咱们的交流群1012951431来获取一份详细的大厂面试资料为你的跳槽多添一份保障。
单例的弊端
优点:
-
一个类只被实例化一次,提供了对唯一实例的受控访问
-
节省系统资源
-
允许可变数目的实例
缺点:
-
一个类只有一个对象,可能造成责任过重,在一定程度上违背了单一职责原则
-
由于单例模式中没有抽象层,因此单例类的扩展有很大困难
-
滥用单例将带来一些负面问题,如:为了节省资源将数据库连接池对象设计为单例类,可能会导致共享连接池对象的程序过多而出现连接池溢出;如果实例化的对象长时间不被利用,系统会认为是垃圾而被回收,这将导致对象状态的丢失
介绍下App启动的完成过程
App启动过程
-
解析
Info.plist
-
加载相关信息,例如闪屏
-
沙盒建立、权限检查
-
Mach-O
加载 -
如果是二进制文件,寻找合适当前CPU类别的部分
-
加载所有依赖的Mach-O文件(递归调用Mach-o加载方法)
-
定位内部、外部指针引用,例如字符串,函数等
-
执行声明为attribute(constructor)的C函数
-
加载类的扩展中的方法
-
C++静态对象加载,调用Objc的+load函数
程序执行
-
main
函数 - 执行
UlApplicationMain
函数 - 创建
UIApplication
对象 - 创建
UIApplicationDelegate
对象并复制 - 读取配置文件
info.plist
,设置程序启动的一些属性 - 创建应用程序的
Main Runloop
循环 -
UlApplicationDelegate
对象开始处理监听事件 - 程序启动之后,首先调用
application.didFinishLaunchingWithOptions:
方法 - 如果
info.plist
中配置了启动的storyBoard
的文件名,则加载storyboard
文件 - 如果没有配置,则根据代码创建
UIWindow
->rootViewController
->显示
引起App启动过慢的因素
-
影响启动性能的因素
App
启动过程中每个步骤都会影响启动性能,但是有些部分所消耗的时间少之又少,另外有些部分根本无法避免,考虑到投入产出比,我们只列出我们可以优化的部分:main
(函数之前耗时的影响因素 -
动态库加载越多,启动越慢。
-
ObjC
类越多,启动越慢 -
C
的constructor
函数越多,启动越慢 -
C++
静态对象越多,启动越慢 -
ObjC
的+load
越多,启动越慢实验证明,在ObjC
类的数目 一样多的情况下,需要加载的动态库越多,App
启动就越慢。同样的,在动态库一样多的情况下,ObjC
的类越多,App
的启动也越慢。需要加载的动态库从1
个上升到10
个的时候,用户几乎感知不到任何分别,但从10
个, 上升到100
个的时候就会变得十分明显。同理,100
个类和1000
个类, 可能也很难查察觉得出,但1000
个类和10000
个类的分别就开始明显起来。同样的,尽量不要写atribute((constrcror))
的C函数
,也尽量不要用到C++
的静态对象;至于ObjC
的+load
方法,似乎大家已经习惯不用它了。任何情况下,能用dispatch_ _once()
来完成的,就尽量不要用到以上的方法。main()
函数之后耗时的影响因素 -
执行
main()
函数的耗时 -
执行
applicationWillFinishLaunching
的耗时 -
rootViewController及其
childViewController
的加载、view
及其subviews
的加载applicationWillFinishLaunching
的耗时
0x8badf00d表示什么?
-
0x8badf00d:
该编码表示应用是因为发生watchdog
超时而被iOS
终止的。通常是应用花费太多时间而无法启动、终止或响应用系统事件。 -
0xbad22222:
该编码表示VolP
应用因为过于频繁重启而被终止 -
Oxdead10cc:
该代码表明应用因为在后台运行时占用系统资源,如通讯录数据库不释放而被终止。 -
Oxdeadfa11:
该代码表示应用是被用户强制退出的。根据苹果文档,强制退出发生在用户长按开关按钮直到出现“滑动来关机”,然后长按Home按钮。强制退出将产生包含0xdeadfa11异常编码的崩溃日志,因为大多数是强制退出是因为应用阻塞了界面。
防止反编译
-
本地数据加密: iOS应用防反编译加密技术之一:对
NSUserDefaults
,sqlite
存储文件数据加密,保护帐号和关键信息 -
URL编码加密: iOS应用防反编译加密技术之二:对程序中出现的
URL
进行编码加密,防此URL
被静态分析 -
网络传输数据加密: iOS应用防反编译加密技术之三:对客户端传输数据提供加密方案,有效防止通过网络接口的拦截获取数据
-
方法体,方法名高级混淆: iOS应用防反编译加密技术之四:对应用程序的方法名和方法体进行混淆,保证源码被逆向后无法解析代码
-
程序结构混排加密: iOS应用防反编译加密技术之五:对应用程序逻辑结构进行打乱混排,保证源码可读性降到最低
-
借助第三方APP加固
需要了解的第三方原理或者底层知识
Runtime
、Runloop
、block
、SDWebImage
、AFN
、YYCache
、GCD
等等底层实现
文末推荐:iOS热门文集
- 面试基础
iOS面试基础知识 (一)
https://github.com/iOS-Mayday/heji
iOS面试基础知识 (二)
https://github.com/iOS-Mayday/heji
iOS面试基础知识 (三)
https://github.com/iOS-Mayday/heji
iOS面试基础知识 (四)
https://github.com/iOS-Mayday/heji
iOS面试基础知识 (五)
https://github.com/iOS-Mayday/heji