我的答案
我有过不少面试和被面试的经历,作为面试官出这份面试题从来就不是为了难倒面试者,而是为了多角度全面的了解面试者从而建立信任。面试的时候最担心的是冷场,面试题只不过个引子,我心底里最希望遇到的面试者是能够举一反三,除了回答问题本身之外,还能自信的旁征博引,深谈其背后原理或者相关的知识理论的。问题本身反而并不怎么重要。这份清单里的问题也并不难,这里我列下我的回答以及从我的角度所期望的答案。
什么是arc?(arc是为了解决什么问题诞生的?)
现在有不少程序员是直接从arc上手的,从没接触过mrc,对arc的理解仅仅停留在apple帮助管理内存的层面。这个问题真正想了解的是对内存管理的理解,retain release虽然不用写了,但arc下还是会有内存泄漏野指针crash的bug存在。如果能从retain count这种内存管理策略的角度去阐述arc诞生的意义就算答对了。如果还能扯下其他类型的策略,比如java里的mark and sweep,那就加分点赞。
请解释以下keywords的区别: assign vs weak, __block vs __weak
这道题属于基础语法题,可以网上搜到答案。不过真有不少同学不知道weak在对象释放后会置为nil。__block关键字的理解稍微难点,因为在arc和mrc下含义(对retain count的影响)完全不同。理解了这几个关键字就能应付使用block时引入retain cycle的风险了。这题还在内存管理的范畴之内。
使用atomic一定是线程安全的吗?
看这题的问法不用想答案肯定是NO。有些人说不出所以然,有些人知道通过property的方式使用才能保证安全,还有人知道这个用来做多线程安全会有性能损耗,更有出色的候选人能谈atomic,synchronized,NSLock,pthread mutex,OSSpinLock的差别。好奇宝宝点我。
描述一个你遇到过的retain cycle例子。(别撒谎,你肯定遇到过)
说没遇到过的我很难相信你有过成熟项目的经历。这题答不出了会扣很多很多分。用过block,写过delegate的肯定都踩过坑。
+(void)load; +(void)initialize;有什么用处?
这题属于runtime范畴,我遇到过能说出对runtime的理解却不知道这两个方法的候选人。所以答不出来也没关系,这属于细节知识点,是加分项,能答出两个message各在什么阶段接收就可以了。
为什么其他语言里叫函数调用, objective c里则是给对象发消息(或者谈下对runtime的理解)
这题考查的是objective c这门语言的dynamic特性,需要对比c++这类传统静态方法调用才能理解。最好能说出一个对象收到message之后的完整的流程是如何的。对runtime有完整理解的候选人还能说出oc的对象模型。
什么是method swizzling?
说了解runtime但没听过method swizzling是骗人的。这题很容易搜到答案。定位一些疑难杂症bug,hack老项目实现,阅读第三方源码都有机会接触到这个概念。
UIView和CALayer是啥关系?
能答出UIView是CALayer的delegate就及格了,能说出UIView主要处理事件,CALayer负责绘制就更好,再聊下二者在使用过程中对动画流畅性影响的注意点就superb。UI流畅性是个大话题,推荐看下这两篇文章。中餐,西餐。
如何高性能的给UIImageView加个圆角?(不准说layer.cornerRadius!)
这题讨论的最多,还有说美工切图就搞定的。答主在项目里做过圆角头像的处理,里面的坑还真不少。cornerRadius会导致offscreen drawing有性能问题,美工切图无法适用有背景图的场景,即使加上shouldRasterize也有cache实效问题。正确的做法是切换到工作线程利用CoreGraphic API生成一个offscreen UIImage,再切换到main thread赋值给UIImageView。这里还涉及到UIImageView复用,圆角头像cache缓存(不能每次都去绘制),新旧头像替换等等逻辑。还有其他的实现方式,但思路离不开工作线程与主线程切换。
使用drawRect有什么影响?(这个可深可浅,你至少得用过。。)
不少同学都用过drawRect或者看别人用过,但不知道这个api存在的含义。这不仅仅是另一种做UI的方式。drawRect会利用CPU生成offscreen bitmap,从而减轻GPU的绘制压力,用这种方式最UI可以将动画流畅性优化到极致,但缺点是绘制api复杂,offscreen cache增加内存开销。UI动画流畅性的优化主要平衡CPU和GPU的工作压力。推荐一篇文章:西餐
ASIHttpRequest或者SDWebImage里面给UIImageView加载图片的逻辑是什么样的?(把UIImageView放到UITableViewCell里面问更赞)
很多同学没有读源码的习惯,别人的轮子拿来只是用用却不知道真正的营养都在源代码里面。这两个经典的framework代码并不复杂,很值得一读。能对一个UIImageView怎么通过url展示一张图片有完整的理解。涉及到的知识点也非常多,UITableViewCell的复用,memory cache, disk cache, 多线程切换,甚至http协议本身都需要有一定的涉及。
麻烦你设计个简单的图片内存缓存器(移除策略是一定要说的)
内存缓存是个通用话题,每个平台都会涉及到。cache算法会影响到整个app的表现。候选人最好能谈下自己都了解哪些cache策略及各自的特点。常见的有FIFO,LRU,LRU-2,2Q等等。由于NSCache的缓存策略不透明,一些app开发者会选择自己做一套cache机制,其实并不难。
讲讲你用Instrument优化动画性能的经历吧(别问我什么是Instrument)
Apple的instrument为开发者提供了各种template去优化app性能和定位问题。很多公司都在赶feature,并没有充足的时间来做优化,导致不少开发者对instrument不怎么熟悉。但这里面其实涵盖了非常完整的计算机基础理论知识体系,memory,disk,network,thread,cpu,gpu等等,顺藤摸瓜去学习,是一笔巨大的知识财富。动画性能只是其中一个template,重点还是理解上面问题当中CPU GPU如何配合工作的知识。
loadView是干嘛用的?
不要就简单的告诉我没用过,至少问下我有什么用。。这里是apple给开发者自己设置custom view的位置。说UI熟悉的一定要知道。
viewWillLayoutSubView你总是知道的。。
controller layout触发的时候,开发者有机会去重新layout自己的各个subview。说UI熟悉的一定要知道。
GCD里面有哪几种Queue?你自己建立过串行queue吗?背后的线程模型是什么样的?
两种queue,串行和并行。main queue是串行,global queue是并行。有些开发者为了在工作线程串行的处理任务会自己建立一个serial queue。背后是苹果维护的线程池,各种queue要用线程都是这个池子里取的。GCD大家都用过,但很多关键的概念不少人都理解的模凌两可。串行,并行,同步,异步是GCD的核心概念。
用过coredata或者sqlite吗?读写是分线程的吗?遇到过死锁没?咋解决的?
没用过sqlite是说不过去的。用过CoreData的肯定有很多血泪史要说。多谢线程模型你肯定做过比较选择。死锁是啥肯定也是要知道的,没遇到过至少能举个简单的例子来说明。单个线程可以死锁(main thread里dispatch_sync到main queue),多个线程直接也可以死锁(A,B线程互相持有对方需要的资源且互相等待)。
http的post和get啥区别?(区别挺多的,麻烦多说点)
这个可以说很多。不希望听到的答案有
两个差不多,随便用一个。
post比get安全(其实两个都不安全)
能说下两个http格式有什么不同,各自应用的场景就合格了。更多可以阅读下这个答案。
我知道你大学毕业过后就没接触过算法数据结构了,但是请你一定告诉我什么是Binary search tree? search的时间复杂度是多少?我很想知道!
很多人都很排斥数据结构和算法题,我个人意见是复杂的可以不知道,基础的一定要了解。时间复杂度是什么得知道,list,queue,stack,table,tree这些都要明白是啥。连hash表的概念都不知道怎么能保证在写代码的时候注意性能呢。
隐藏关卡😓
其实当初写这份答案的时候并没有准备什么隐藏关卡,只不过有一些从自己这些年项目经历里总结出来的有深度的知识点,感觉可以难倒不少同学:p。求隐藏关卡的同学真不少,近期我会再准备一份进阶版面试题,权当作隐藏关卡。面向的对象是3~5年iOS开发经验的同学。再次申明下:这只是一份面试题。
看到这个题目是一个群里的朋友发的,感谢那个兄弟,看到MrPeak大大出的题目啊 好开心,试着答,各位大大请轻喷,刚好不怎么忙,带着耳机听歌,答了一个小时,真舒服啊,看到这些题目好多都不怎么知道,恶补,学习。
1.NSString如何计算字符的个数?
应该是用countElements的函数来统计字符串所包含的字符个数,把参数为要统计的字符串就好了。
但是需要注意以下的几个点:
1.因为不同的Unicode字符,同样的字符不同的编码都可能导致占用不同的内存。所以按正常来说,字符串中的每个字符会占用不同的内存。因此,只能通过遍历字符串中的每个字符来计算字符串的长度。但是当在处理一个特别长的字符串的话,可以通过遍历遍历整个字符串,这样既可以算出字符串的长度了。
2.同一个字符串,countElements计算出来的字符个数与NSString的length计算出来的长度也不一定总是一样的的。因为NSString的长度是基UTF-16编码的编码来计算的,而不是Unicode编码的个数。但是,好像在Swift中可以使用字符串的utf16count属性来来获得原来NSString的length值,忘记了,很久没用Swift了。
2.PKI体系当中加密和签名有什么区别?
这个问题我来答的话,应该先说说PKI是一种安全技术, 数字签名和加密基本原理是什么,在说区别,话说基本原理我也不记得了,就大概记得一个HUSH函数什么的了,他们的过程都是使用公开密钥体系,但实现的过程是不同的,相反,使用的密钥对也不同。
1.数字签名是发送方的密钥对,发送方用自己的私有密钥进行加密,接收方用发送方的公开密钥进行解密,大致就是这样吧,它一个一对多的关系,任何拥有发送方公开密钥的人都可以验证数字签名的正确性,还有只采用了非对称密钥加密算法,能保证发送信息的完整性、身份认证和不可否认性。
2.数字加密是接收方的密钥对,这是多对一的关系,任何知道接收方公开密钥的人都可以向接收方发送加密信息,只有唯一拥有接收方私有密钥的人才能对信息解密,用的对称密钥加密算法和非对称密钥加密算法相结合的方法,它能保证发送信息保密性。
3.如何自己高效实现NSUserDefault?
这个,真心不知道,peak大大。只知道NSUserDefaults是定时把缓存中的数据写入磁盘的,而不是即时写入,为了防止在写完NSUserDefaults后程序退出导致的数据丢失,可以在写入数据后使用synchronize强制立即将数据写入磁盘,现在要高效的实现NSUserDefaults,个人见解就是不频繁的使用synchornize,自定义一个类,再存取时通过NSData做载体。
4.解释下tcp的慢启动特性。
现在公司应该都是在避免慢启动,做性能优化吧,优化应该可以尽量把大量小文件放在一个TCP连接中排队传输吧,没试验过,自己YY的。
这问的是Tcp慢启动的特点,难道就是它在新建立的连接不能够一开始就发送大尺寸的数据包,而只能从一个小尺寸的包开始发送,在发送和数据被对方确认的过程中去计算对方的接收速度,来逐步增加每次发送的数据量,但是这样的话 性能呢,请科普下,谢谢。
5.如何用HTTP实现长连接?
首先HTTP是无状态的,要维持一个长连接可以用心跳包啊,公司项目第一个版本就是这样用的,然后各种原因,各种呵呵呵,丢包,沾包,应该可以对http连接进行轮询,但是http定时轮询会存在延迟 用户体验就不好了 或者用socket流方法,监听服务器消息
6.HTTP2.0针对同一个域名的多个请求,会建立多少个tcp连接?
一个吗?不是很清楚啊。
7.数据库建表的时候索引有什么用?
创建索引可以大大提高系统的性能,加快数据的检索速度,加速表和表之间的连接,保证数据库表中每一行数据的唯一性,但是有些列不应该创建索引,这又要考虑到性能了,所以具体情况具体分析了。
8.Full Text Search为什么快?
这我不是后台不是很了解,问题偏后台系统多一点点了,但是自己会写一点点PHP,好像是用空间来换时间,通过分词器,降索引的表分割啥的,不是很清楚原理啊,看来要系统学下后台语言。
9.iOS下如何实现指定线程数目的线程池?
这个问题问的太深了吧,一般开发根本用不到,还好最近在看线程安全方面的书籍,要不然问到真的会懵逼。
1.循环通过pthread_create创建线程,创建s_tfthread对象做为线程句,加入线程数组,s_tftask_content->methord初始化为空函数
2.创建任务执行函数,执行完通过task初始化函数后,在执行函数中通过pthread_cond_wait信号将当前创建的线程挂起
3.创建完之后,程序中将会有n个挂起状态的线程,当需要执行新的task的时候查找,我们就可以根据不同的task标志在k_threads中查询出空闲线程,并创建新的s_tftask_content加入s_tfthread的任务列表,通过pthread_cond_signal重新唤醒该线程继续执行任务
10.介绍下iOS设备获取唯一设备号的历史变迁。
这个没做过几年开发的真心不知道,iOS中获取设备唯一标示符的方法一直随版本的更新而变化。iOS 2.0版本以后UIDevice提供一个获取设备唯一标识符的方法uniqueIdentifier,但是好像是iOS 4还是iOS5就被苹果废弃掉了,然后iOS6是用WiFi的mac地址来获取的,iOS7后大家都知道了,主要是由于苹果又坑爹了,封杀mac地址,但是推荐大家用KeyChain来保存获取到的UDID,因为APP删了再装回来,也可以从KeyChain中读取回来,哈哈,公司的项目都是把UDID存在KeyChain。
11.函数式编程当中的 first-class function是什么意思呢?
这个问题好像以前就在知乎看过,就是类型,定义了一个可以操作的取值的集合,就像C语言的int类型一样,可进行加减乘除等操作,但是它的设计又有一个模块复用和访存控制,这样设计的原因应该是让我们更好用吧,没有深究过这个。
12.如何使用runtime hook一个class的某个方法,又如何hook某个instance的方法?
做到这里在电脑码字快三十分钟了啊,peak大大,你问的问题都好难回答啊,要分各种情况。这题也是首先要考虑 hook是否有公开头文件的类,有的话写一个Utility函数,再使用category,没有的话就建一个类作为新函数载体,然后先为被hook的类增加函数,再替换,没错就是这个样子。后面如何h如何hook某个instance的方法,应该可以定义一个函数指针变量,hook时将要调用的地址赋给这个变量,调用时把这个变量当作函数来用就行了。
13.谈下Objective C都有哪些锁机制,你一般用哪个?
synchronized、NSLOCK、GCD、递归锁、分布锁、同步锁(这个是C语言的),一般用GCD,这里就不说了,真心不想码字了,peak大大可能会问,为什么,又要把各种锁机制对比,这我会疯,我脑袋要死机了,重启中…
14.聊下HTTP post的body体使用form-urlencoded和multipart/form-data的区别。
http定义了与服务器交互的不同方法,最基本的方法有4种,分别是GET,POST,PUT,DELETE,刚好公司上个项目都用了这四种方式的请求,怎么都是踩过得坑。
form-urlencoded是默认的mime内容编码类型,是通用的,但是它在传输比较大的二进制或者文本数据时效率极低。
multipart/form-data是当上传文件或者二进制数据和非ASCII数据使用。
15.让你设计一种机制检测UIViewController的内存泄漏,你会怎么做?
这个问题没有考虑过,都是自己写单元测试什么的来测试,都是些基础的测试,一般都是用Instrument来测试一些东西的。自己设计的话,主要还是要考虑一个VC的生命周期。
16.通过[UIImage imageNamed:]生成的对象什么时候被释放?
应该是到@autoreleasepool 结束的时候才释放的,但是我都是用这imageWithContentsOfFile方法加载图片的
17.applicationWillEnterForeground和applicationDidBecomeActive都会在哪些场景下被调用?举例越多越好。
推送、做支付的时候,跳到人家运用,后台杀进程的时候、做IM的时候、第三方授权分享登录回调情况下等等
18.如何终止正在运行的工作线程?
在线程中调用exit、pthread_exit、pthread_kill、pthread_cance都行吧
19.穷举iOS下所有的本地持久化方案。
沙盒
plist文件(属性列表)
preference(偏好设置)
NSKeyedArchiver(归档)
SQLite 3
CoreData
还有请补充...
20.如果公司强制996,你有什么心里话要对老板说吗?
没什么话,习惯了,主要想要对产品经理说你的需求能不能想好在做,不要瞎搞,谢谢。看到这个题目是一个群里的朋友发的,感谢那个兄弟,看到MrPeak大大出的题目啊 好开心,试着答,各位大大请轻喷,刚好不怎么忙,带着耳机听歌,答了一个小时,真舒服啊,看到这些题目好多都不怎么知道,恶补,学习。
1.NSString如何计算字符的个数?
应该是用countElements的函数来统计字符串所包含的字符个数,把参数为要统计的字符串就好了。
但是需要注意以下的几个点:
1.因为不同的Unicode字符,同样的字符不同的编码都可能导致占用不同的内存。所以按正常来说,字符串中的每个字符会占用不同的内存。因此,只能通过遍历字符串中的每个字符来计算字符串的长度。但是当在处理一个特别长的字符串的话,可以通过遍历遍历整个字符串,这样既可以算出字符串的长度了。
2.同一个字符串,countElements计算出来的字符个数与NSString的length计算出来的长度也不一定总是一样的的。因为NSString的长度是基UTF-16编码的编码来计算的,而不是Unicode编码的个数。但是,好像在Swift中可以使用字符串的utf16count属性来来获得原来NSString的length值,忘记了,很久没用Swift了。
2.PKI体系当中加密和签名有什么区别?
这个问题我来答的话,应该先说说PKI是一种安全技术, 数字签名和加密基本原理是什么,在说区别,话说基本原理我也不记得了,就大概记得一个HUSH函数什么的了,他们的过程都是使用公开密钥体系,但实现的过程是不同的,相反,使用的密钥对也不同。
1.数字签名是发送方的密钥对,发送方用自己的私有密钥进行加密,接收方用发送方的公开密钥进行解密,大致就是这样吧,它一个一对多的关系,任何拥有发送方公开密钥的人都可以验证数字签名的正确性,还有只采用了非对称密钥加密算法,能保证发送信息的完整性、身份认证和不可否认性。
2.数字加密是接收方的密钥对,这是多对一的关系,任何知道接收方公开密钥的人都可以向接收方发送加密信息,只有唯一拥有接收方私有密钥的人才能对信息解密,用的对称密钥加密算法和非对称密钥加密算法相结合的方法,它能保证发送信息保密性。
3.如何自己高效实现NSUserDefault?
这个,真心不知道,peak大大。只知道NSUserDefaults是定时把缓存中的数据写入磁盘的,而不是即时写入,为了防止在写完NSUserDefaults后程序退出导致的数据丢失,可以在写入数据后使用synchronize强制立即将数据写入磁盘,现在要高效的实现NSUserDefaults,个人见解就是不频繁的使用synchornize,自定义一个类,再存取时通过NSData做载体。
4.解释下tcp的慢启动特性。
现在公司应该都是在避免慢启动,做性能优化吧,优化应该可以尽量把大量小文件放在一个TCP连接中排队传输吧,没试验过,自己YY的。
这问的是Tcp慢启动的特点,难道就是它在新建立的连接不能够一开始就发送大尺寸的数据包,而只能从一个小尺寸的包开始发送,在发送和数据被对方确认的过程中去计算对方的接收速度,来逐步增加每次发送的数据量,但是这样的话 性能呢,请科普下,谢谢。
5.如何用HTTP实现长连接?
首先HTTP是无状态的,要维持一个长连接可以用心跳包啊,公司项目第一个版本就是这样用的,然后各种原因,各种呵呵呵,丢包,沾包,应该可以对http连接进行轮询,但是http定时轮询会存在延迟 用户体验就不好了 或者用socket流方法,监听服务器消息
6.HTTP2.0针对同一个域名的多个请求,会建立多少个tcp连接?
一个吗?不是很清楚啊。
7.数据库建表的时候索引有什么用?
创建索引可以大大提高系统的性能,加快数据的检索速度,加速表和表之间的连接,保证数据库表中每一行数据的唯一性,但是有些列不应该创建索引,这又要考虑到性能了,所以具体情况具体分析了。
8.Full Text Search为什么快?
这我不是后台不是很了解,问题偏后台系统多一点点了,但是自己会写一点点PHP,好像是用空间来换时间,通过分词器,降索引的表分割啥的,不是很清楚原理啊,看来要系统学下后台语言。
9.iOS下如何实现指定线程数目的线程池?
这个问题问的太深了吧,一般开发根本用不到,还好最近在看线程安全方面的书籍,要不然问到真的会懵逼。
1.循环通过pthread_create创建线程,创建s_tfthread对象做为线程句,加入线程数组,s_tftask_content->methord初始化为空函数
2.创建任务执行函数,执行完通过task初始化函数后,在执行函数中通过pthread_cond_wait信号将当前创建的线程挂起
3.创建完之后,程序中将会有n个挂起状态的线程,当需要执行新的task的时候查找,我们就可以根据不同的task标志在k_threads中查询出空闲线程,并创建新的s_tftask_content加入s_tfthread的任务列表,通过pthread_cond_signal重新唤醒该线程继续执行任务
10.介绍下iOS设备获取唯一设备号的历史变迁。
这个没做过几年开发的真心不知道,iOS中获取设备唯一标示符的方法一直随版本的更新而变化。iOS 2.0版本以后UIDevice提供一个获取设备唯一标识符的方法uniqueIdentifier,但是好像是iOS 4还是iOS5就被苹果废弃掉了,然后iOS6是用WiFi的mac地址来获取的,iOS7后大家都知道了,主要是由于苹果又坑爹了,封杀mac地址,但是推荐大家用KeyChain来保存获取到的UDID,因为APP删了再装回来,也可以从KeyChain中读取回来,哈哈,公司的项目都是把UDID存在KeyChain。
11.函数式编程当中的 first-class function是什么意思呢?
这个问题好像以前就在知乎看过,就是类型,定义了一个可以操作的取值的集合,就像C语言的int类型一样,可进行加减乘除等操作,但是它的设计又有一个模块复用和访存控制,这样设计的原因应该是让我们更好用吧,没有深究过这个。
12.如何使用runtime hook一个class的某个方法,又如何hook某个instance的方法?
做到这里在电脑码字快三十分钟了啊,peak大大,你问的问题都好难回答啊,要分各种情况。这题也是首先要考虑 hook是否有公开头文件的类,有的话写一个Utility函数,再使用category,没有的话就建一个类作为新函数载体,然后先为被hook的类增加函数,再替换,没错就是这个样子。后面如何h如何hook某个instance的方法,应该可以定义一个函数指针变量,hook时将要调用的地址赋给这个变量,调用时把这个变量当作函数来用就行了。
13.谈下Objective C都有哪些锁机制,你一般用哪个?
synchronized、NSLOCK、GCD、递归锁、分布锁、同步锁(这个是C语言的),一般用GCD,这里就不说了,真心不想码字了,peak大大可能会问,为什么,又要把各种锁机制对比,这我会疯,我脑袋要死机了,重启中…
14.聊下HTTP post的body体使用form-urlencoded和multipart/form-data的区别。
http定义了与服务器交互的不同方法,最基本的方法有4种,分别是GET,POST,PUT,DELETE,刚好公司上个项目都用了这四种方式的请求,怎么都是踩过得坑。
form-urlencoded是默认的mime内容编码类型,是通用的,但是它在传输比较大的二进制或者文本数据时效率极低。
multipart/form-data是当上传文件或者二进制数据和非ASCII数据使用。
15.让你设计一种机制检测UIViewController的内存泄漏,你会怎么做?
这个问题没有考虑过,都是自己写单元测试什么的来测试,都是些基础的测试,一般都是用Instrument来测试一些东西的。自己设计的话,主要还是要考虑一个VC的生命周期。
16.通过[UIImage imageNamed:]生成的对象什么时候被释放?
应该是到@autoreleasepool 结束的时候才释放的,但是我都是用这imageWithContentsOfFile方法加载图片的
17.applicationWillEnterForeground和applicationDidBecomeActive都会在哪些场景下被调用?举例越多越好。
推送、做支付的时候,跳到人家运用,后台杀进程的时候、做IM的时候、第三方授权分享登录回调情况下等等
18.如何终止正在运行的工作线程?
在线程中调用exit、pthread_exit、pthread_kill、pthread_cance都行吧
19.穷举iOS下所有的本地持久化方案。
沙盒
plist文件(属性列表)
preference(偏好设置)
NSKeyedArchiver(归档)
SQLite 3
CoreData
还有请补充...
20.如果公司强制996,你有什么心里话要对老板说吗?
没什么话,习惯了,主要想要对产品经理说你的需求能不能想好在做,不要瞎搞,谢谢。