可能碰到的iOS笔试面试题(11)--报错警告调试

报错警告调试

你在实际开发中,有哪些手机架构与性能调试经验

  • 刚接手公司的旧项目时,模块特别多,而且几乎所有的代码都写在控制器里面,比如UI控件代码、网络请求代码、数据存储代码
  • 接下来采取MVC模式进行封装、重构
    • 自定义UI控件封装内部的业务逻辑
    • 封装网络请求工具类(降低耦合)
    • 封装数据存储工具类

BAD_ACCESS在什么情况下出现?

这种问题是经常遇到的,在开发时经常会出现BAD_ACCESS。原因是访问了野指针,比如访问已经释放对象的成员变量或者发消息、死循环等。

如何调试BAD_ACCESS错误?

出现BAD_ACCESS错误,通常是访问了野指针,比如访问了已经释放了的对象。快速定位问题的步骤有:
1.  重写对象的respondsToSelector方法,先找到出现EXECBADACCESS前访问的最后一个object
2.  设置Enable Zombie Objects
3.  设置全局断点快速定位问题代码所在行,接收所有的异常
4.  Xcode7已经集成了BAD_ACCESS捕获功能:Address Sanitizer,与步骤2一样设置
5. analyze也行(不一定管用)

什么时候会报 unrecognized selector 异常?

  • 当调用对象(子类,各级父类)中不含有对应方法的时候,并且依旧没有给出“消息转发”的具体方案的时候,程序在运行时会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,然后提示打不到响应的方法。到此,动态解析的流程就结束了。

有哪些常见的 Crash 场景?

  • 访问了僵尸对象
  • 访问了不存在的方法
  • 数组越界
  • 在定时器下一次回调前将定时器释放,会Crash

lldb(gdb)常用的调试命令?

•   p 输出基本类型//p (int)[[[self view] subviews] count]
•   po 用于输出 Objective-C 对象//po [self view]
•   expr 可以在调试时动态执行指定表达式,并将结果打印出来。常用于在调试过程中修改变量的值。//源代码中 a = 1 ;expr a=2 输出结果:(int) $0 = 2

如果一个函数10次中有7次正确,3次错误,问题可能出现在哪里?

这样的问题通过应聘者的分析,可以知道应聘者的功底如何。很多人的回答会是很简单的,没有从多方面去分析。这样的问题也是很有意义的,在项目开发中所产生的bug,有的时候会出现这样的情况,而代码量比较大且业务比较复杂时,通过其他工具并不能分析出来是什么bug,但是我们却可以根据出现的频率推测。笔者把这个问题当作测试部反馈过来的bug描述问题来分析一下。
参考答案:
从问题描述可知,bug不会必现的,因此无法直接定位出错之处。从以下角度出现来分析可能出错之处:
1.  因出错并不是崩溃,因此没有错误日志可看。第一步就是分析函数中的所有分支,是否在语法上存在可能缺少条件的问题。所以,检查所有的分支,确保每个分支执行的结果的正确的
2.  检测函数的参数,保证必传参数不能为空,若为空应该抛出异常。因此,用断言检测参数的正确性是很重要的。
3.  检测函数中每个分支所调用的函数返回结果是正确的,其实就是一个递归的过程(步骤1、2)

你一般是如何调试Bug的?

这个问题看起来很笼统,但又一针见血。通过应聘者的回答,可很直观地看出这个应聘者的处理bug的能力,以及其解决问题的思维。
参考答案:
Bug分为测试中的Bug和线上的Bug:
•   线上Bug:项目使用了友盟统计,因此会有崩溃日志,通过解析dYSM可以直接定位到大部分bug崩溃之处。解决线上bug需要从主干拉一个新的分支,解决bug并测试通过后,再合并到主干,然后上线。若是多团队开发,可以将fix bug分支与其他团队最近要上线的分支集成,然后集成测试再上线。
•   测试Bug:根据测试所反馈的bug描述,若语义不清晰,则直接找到提bug人,操作给开发人员看,最好是可以bug复现。解决bug时,若能根据描述直接定位bug出错之处,则好处理;若无法直观定位,则根据bug类型分几种处理方式,比如崩溃的bug可以通过instruments来检测、数据显示错误的bug,则需要阅读代码一步步查看逻辑哪里写错。
对于开发中出现的崩溃或者数据显示不正常,那就需要根据经验或者相关工具来检测可能出错之处。当然,团队内沟通解决是最好的。

获取一台设备唯一标识的方法有哪些?

  • 现在常用的是用UUID + keychain结合来实现这个需求。

  • UUID是Universally Unique Identifier的缩写,中文意思是通用唯一识别码。它是让分布式系统中的所有元素,都能有唯一的辨识资讯,而不需要透过中央控制端来做辨识资讯的指定。这样,每个人都可以建立不与其它人冲突的 UUID。在此情况下,就不需考虑数据库建立时的名称重复问题。苹果公司建议使用UUID为应用生成唯一标识字符串。

//获取一个UUID
 - (NSString*)uuid {
    CFUUIDRef uuid = CFUUIDCreate( nil );
    CFStringRef uuidString = CFUUIDCreateString( nil, uuid );
    NSString * result = (NSString *)CFBridgingRelease(CFStringCreateCopy( NULL, uuidString));
    CFRelease(uuid);
    CFRelease(uuidString);
    return result;
}
  • 现在我们获取到了一个UUID,虽然这个标识是唯一的,但是这样还是无法保证每一次的唯一性,因为当你每次调用这个方法或者把应用卸载了,UUID会重新生成一个不同的。这个时候keychain就起到了作用。

  • 所以整个逻辑是这样的:先从keychain取UUID,如果能取到,就用这个比对,如果取不到就重新生成一个保存起来。keychain独立在App之外,是和系统统一等级的,所以你不用担心它挂掉。

  • keychain是苹果公司Mac OS中的密码管理系统。它在Mac OS 8.6中被导入,并且包括在了所有后续的Mac OS版本中,包括Mac OS X。一个钥匙串可以包含多种类型的数据:密码(包括网站,FTP服务器,SSH帐户,网络共享,无线网络,群组软件,加密磁盘镜像等),私钥,电子证书和加密笔记等。iOS端同样有个keychain帮助我们管理这些敏感信息。

  • 使用过keychain保存过账号密码的童鞋应该对这个工具非常了解,在这里不做过多解释。使用keychain需要导入Security.framework和KeychainItemWrapper.h/.m,KeychainItemWrapper.h/.m搜一下可以下载下来,拖入工程中。保存UUID代码如下:

- (void)saveUuidWithKeyChain {
    KeychainItemWrapper *keychainItem = [[KeychainItemWrapper alloc]
                                         initWithIdentifier:@"UUID" accessGroup:@"com.xxx.www"];
    NSString *strUUID = [keychainItem objectForKey:(id)kSecValueData];
    if (strUUID == nil || [strUUID isEqualToString:@""])
    {
        [keychainItem setObject:[self uuid] forKey:(id)kSecValueData];
    }
}
注:这个方法中accessGroup:这个参数如果一些App设置相同的话,是可以共享的。

  • 从keychain获取UUID的方法如下:
- (NSString *)getKeychain {
    KeychainItemWrapper *keychainItem = [[KeychainItemWrapper alloc]
                                         initWithIdentifier:@"UUID" accessGroup:@"com.xxx.www"];
    NSString *strUUID = [keychainItem objectForKey:(id)kSecValueData];
    return strUUID;
}
  • 至此,基本上唯一标识的几个方法算是写完了,大家可以测试一下,卸载应用再重新装,从keychain读取的UUID还是和之前一样。

  • 但这里有个不确定因素,就是手机系统恢复出厂设置或者抹掉所有数据的话,这个方法也可能不起作用了,因为它是依靠钥匙串在生存,钥匙串挂掉的话它也就失效了。

你一般是怎么用 Instruments 的?

  • 这个问题也就是考察下你经验如何了, Instruments里面工具很多,也没必要逐一说明,挑几个常用的说下就好

  • 参考答案:

  • Time Profiler:性能分析

  • Zombies:检查是否访问了僵尸对象,但是这个工具只能从上往下检查,不智能

  • Allocations:用来检查内存,写算法的那批人也用这个来检查

  • Leaks:检查内存,看是否有内存泄露

你一般是如何调试 Bug 的?

  • 查看异常报告
  • 配置相关环境,重现bug
  • 代码检查
  • 用测试案例来捕获bug
  • 可以请同事一同来审查问题,有些时候当局者迷,旁观者清。

如何对iOS设备进行性能测试?

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系统语言环境变化时

文章如有问题,请留言,我将及时更正。

满地打滚卖萌求赞,如果本文帮助到你,轻点下方的红心,给作者君增加更新的动力。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,033评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,725评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,473评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,846评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,848评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,691评论 1 282
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,053评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,700评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,856评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,676评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,787评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,430评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,034评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,990评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,218评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,174评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,526评论 2 343

推荐阅读更多精彩内容

  • 面试笔试都是必考语法知识的。请认真复习和深入研究OC。 Objective-C 方法和选择器有何不同?(Diffe...
    b485c88ab697阅读 5,674评论 0 35
  • 转至元数据结尾创建: 董潇伟,最新修改于: 十二月 23, 2016 转至元数据起始第一章:isa和Class一....
    40c0490e5268阅读 1,678评论 0 9
  • 设计模式是什么? 你知道哪些设计模式,并简要叙述?设计模式是一种编码经验,就是用比较成熟的逻辑去处理某一种类型的事...
    irenb阅读 5,183评论 1 20
  • 设计模式是什么? 你知道哪些设计模式,并简要叙述? 设计模式是一种编码经验,就是用比较成熟的逻辑去处理某一种类型的...
    不懂后悔阅读 823评论 0 53
  • 设计模式是什么? 你知道哪些设计模式,并简要叙述? 设计模式是一种编码经验,就是用比较成熟的逻辑去处理某一种类型的...
    small_Sun阅读 450评论 0 4