<h1>1、你在实际开发中,有哪些手机架构与性能调试经验</h1>
1 > 刚接手公司的旧项目时,模块特别多,而且几乎所有的代码都写在控制器里面,比如UI控件代码、网络请求代码、数据存储代码
2> 接下来采取MVC模式进行封装、重构:
a> 自定义UI控件封装内部的业务逻辑
b> 封装网络请求工具类(降低耦合)
c> 封装数据存储工具类
<h1>2、BAD_ACCESS在什么情况下出现?</h1>
这种问题是经常遇到的,在开发时经常会出现BAD_ACCESS。
原因是访问了野指针,比如访问已经释放对象的成员变量或者发消息、死循环等。
<h1>3、如何调试BAD_ACCESS错误?</h1>
出现BAD_ACCESS错误,通常是访问了野指针,比如访问了已经释放了的对象。快速定位问题的步骤有:
1. 重写对象的respondsToSelector方法,先找到出现EXECBADACCESS前访问的最后一个object
2. 设置Enable Zombie Objects
3. 设置全局断点快速定位问题代码所在行,接收所有的异常
4. Xcode7已经集成了BAD_ACCESS捕获功能:Address Sanitizer,与步骤2一样设置
5. analyze也行(不一定管用)
<h1>4、什么时候会报 unrecognized selector 异常?</h1>
当调用对象(子类,各级父类)中不含有对应方法的时候,并且依旧没有给出“消息转发”的具体方案的时候,程序在运行时会crash并抛出 unrecognized selector 异常
objective-c 中的每个方法在运行时会被转为消息发送objc_msgSend(reciver, selector)
例如 [person say]就会被转化为 objc_msgSend(person, @selector(say))
运行时会根据对象(reciever) 的isa 指针找到该对象所对应的类,然后会依次在对应的类,父类,爷爷类,根类中找对应的方法
下面只讲述对象方法的解析过程:
第一步:+ (BOOL)resolveInstanceMethod:(SEL)sel实现方法,指定是否动态添加方法。若返回NO,则进入下一步,若返回YES,则通过class_addMethod函数动态地添加方法,消息得到处理,此流程完毕。
第二步:在第一步返回的是NO时,就会进入- (id)forwardingTargetForSelector:(SEL)aSelector方法,这是运行时给我们的第二次机会,用于指定哪个对象响应这个selector。不能指定为self。若返回nil,表示没有响应者,则会进入第三步。若返回某个对象,则会调用该对象的方法。
第三步:若第二步返回的是nil,则我们首先要通过- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector指定方法签名,若返回nil,则表示不处理。若返回方法签名,则会进入下一步。
第四步:当第三步返回方法方法签名后,就会调用- (void)forwardInvocation:(NSInvocation *)anInvocation方法,我们可以通过anInvocation对象做很多处理,比如修改实现方法,修改响应对象等
第五步:若没有实现- (void)forwardInvocation:(NSInvocation *)anInvocation方法,那么会进入- (void)doesNotRecognizeSelector:(SEL)aSelector方法。若我们没有实现这个方法,那么就会crash,然后提示打不到响应的方法。到此,动态解析的流程就结束了。
<h1>5、有哪些常见的 Crash 场景?</h1>
访问了僵尸对象
访问了不存在的方法
数组越界
在定时器下一次回调前将定时器释放,会Crash
<h1>6、lldb(gdb)常用的调试命令?</h1>
• p 输出基本类型//p (int)[[[self view] subviews] count]
• po 用于输出 Objective-C 对象//po [self view]
• expr 可以在调试时动态执行指定表达式,并将结果打印出来。常用于在调试过程中修改变量的值。//源代码中 a = 1 ;expr a=2 输出结果:(int) $0 = 2
<h1>7、如果一个函数10次中有7次正确,3次错误,问题可能出现在哪里?</h1>
这样的问题通过应聘者的分析,可以知道应聘者的功底如何。很多人的回答会是很简单的,没有从多方面去分析。这样的问题也是很有意义的,在项目开发中所产生的bug,有的时候会出现这样的情况,而代码量比较大且业务比较复杂时,通过其他工具并不能分析出来是什么bug,但是我们却可以根据出现的频率推测。笔者把这个问题当作测试部反馈过来的bug描述问题来分析一下。
参考答案:
从问题描述可知,bug不会必现的,因此无法直接定位出错之处。从以下角度出现来分析可能出错之处:
1. 因出错并不是崩溃,因此没有错误日志可看。第一步就是分析函数中的所有分支,是否在语法上存在可能缺少条件的问题。所以,检查所有的分支,确保每个分支执行的结果的正确的
2. 检测函数的参数,保证必传参数不能为空,若为空应该抛出异常。因此,用断言检测参数的正确性是很重要的。
3. 检测函数中每个分支所调用的函数返回结果是正确的,其实就是一个递归的过程(步骤1、2)
<h1>8、你一般是如何调试Bug的?</h1>
个问题看起来很笼统,但又一针见血。通过应聘者的回答,可很直观地看出这个应聘者的处理bug的能力,以及其解决问题的思维。
参考答案:
Bug分为测试中的Bug和线上的Bug:
• 线上Bug:项目使用了友盟统计,因此会有崩溃日志,通过解析dYSM可以直接定位到大部分bug崩溃之处。解决线上bug需要从主干拉一个新的分支,解决bug并测试通过后,再合并到主干,然后上线。若是多团队开发,可以将fix bug分支与其他团队最近要上线的分支集成,然后集成测试再上线。
• 测试Bug:根据测试所反馈的bug描述,若语义不清晰,则直接找到提bug人,操作给开发人员看,最好是可以bug复现。解决bug时,若能根据描述直接定位bug出错之处,则好处理;若无法直观定位,则根据bug类型分几种处理方式,比如崩溃的bug可以通过instruments来检测、数据显示错误的bug,则需要阅读代码一步步查看逻辑哪里写错。
对于开发中出现的崩溃或者数据显示不正常,那就需要根据经验或者相关工具来检测可能出错之处。当然,团队内沟通解决是最好的。
<h1>9、你一般是怎么用 Instruments 的?</h1>
这个问题也就是考察下你经验如何了, Instruments里面工具很多,也没必要逐一说明,挑几个常用的说下就好
参考答案:
Time Profiler:性能分析
Zombies:检查是否访问了僵尸对象,但是这个工具只能从上往下检查,不智能
Allocations:用来检查内存,写算法的那批人也用这个来检查
Leaks:检查内存,看是否有内存泄露
<h1>10、你一般是如何调试 Bug 的?</h1>
查看异常报告
配置相关环境,重现bug
代码检查
用测试案例来捕获bug
可以请同事一同来审查问题,有些时候当局者迷,旁观者清。
<h1>11、如何对iOS设备进行性能测试?</h1>
Profile-> Instruments ->Time Profiler 进行性能测试!
测试iOS版的 App 注意事项分享以下几点:
1.app使用过程中,接听电话。可以测试不同的通话时间的长短,对于通话结束后,原先打开的app的响应,比如是否停留在原先界面,继续操作时的相应速度等。
2.app使用过程中,有推送消息时,对app的使用影响
3.设备在充电时,app的响应以及操作流畅度
4.设备在不同电量时(低于10%,50%,95%),app的响应以及操作流畅度
5.意外断电时,app数据丢失情况
6.网络环境变化时,app的应对情况如何:是否有适当提示?从有网络环境到无网络环境时,app的反馈如何?从无网络环境回到有网络环境时,是否能自动加载数据,多久才能开始加载数据
7.多点触摸的情况
8.跟其他app之间互相切换时的响应
9.进程关闭再重新打开的反馈
10.IOS系统语言环境变化时