最近觉得现在所在公司平台用户量太少,自身技术已经到了一个瓶颈,是时候需要换一个用户量多的平台,好好研究下iOS的性能优化、内存优化等问题了。

所面试的公司由于一些默认的规定,就不多说了,大致是面了一个下午,从2点到下午6点半,正式拿到offer,先从笔试题开始说起吧。

笔试题:15道题,稍微有些多了,做了将近一个半小时。从笔试题就可以稍微看出一个公司的iOS团队技术水平如何,以及他们是不是真的想要招人。我春节之前投过一波简历,当时挑了一家公司去,还没技术面,只是看了他们的面试题,就知道了这个公司大概不会录用我,因为那面试题太水了,一看就是百度过来还没有筛选的。做完之后,面我的面试官就和我说,这套面试题从他入职以来到现在就没换过,我就呵呵了,明显是没招人的打算,叫我过来纯属浪费时间。

第一道,是C\OC\C++里面的一些常识吧,就是nil、Null、Nil的区别

这道题我答的不好,只是从C\OC语法的角度上解释了下它们的区别,回来百度下,看了其他人的回答,该这么写:

nil和null从字面意思来理解比较简单,nil是一个对象,而NULL是一个值,我的理解为nil是将对象设置为空,而null是将基本类型设置为空的,个人感觉有点像属性当中,基本类型分配为assign NSString类型一般分配copy,而对象一般用retain。而且我们对于nil调用方法,不会产生crash或者抛出异常。

nil是一个对象指针为空,Nil是一个类指针为空,NULL是基本数据类型为空。这些可以理解为nil,Nil, NULL的区别吧。

第二道,UIEvent与UITouch的异同

我当时的回答是,UIEvent对象包含一个UITouch对象,这是错误的。实际开发中,我经常用到touches系列API,但是基本没关注UIEvent对象:

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
    [[touches anyObject] locationInView:self.view];
}

经常这么用,主要关注的是UITouch对象,谷歌过来,关于UITouch:

当用户手指触摸屏幕,就会创建一个与这根手指相关联的对象,一根手指对应一个UITouch对象,它保存着与手指相关的信息,比如手指触摸的位置、时间、阶段。

UIEvent对象:

每产生一个事件,就会产生一个UIEvent对象,它称为事件对象,记录事件产生的时刻和类型。

第三道,响应者链条,这是妥妥的送分题,不详细解释了。

第四道,好像是关于assign\copy\retain\nonatomic\atomic的使用场合吧,也算是送分题,需要注意的是,即使是atomic也不能保证线程安全的,这个我测试过,相应的资料谷歌下,应该有的。

第五道,好像是为什么delegate用assign,而不用retain,送分题,不解释。

第六道,就是说,一个autoreleasepool在什么时候被销毁?

如果不知道RunLoop机制,这里建议回答,在线程被销毁之前会销毁autoreleasepool,对pool立面的所有对象做一次release操作。

正确的回答,应该是在RunLoop进入休眠之前,会销毁pool,在RunLoop被唤醒时,会创建pool,但是,你既然这么写了,就要做好面试官问你RunLoop相关知识的准备。

第七、八、九、十道,基本就是MRC的内存管理,判断是否正确以及纠错。

比如说:

    NSString *name = [[NSString alloc] initWithString:@"lisi"];
    [name retain];
    [name release];
    [name autorealse];

需要在后面写出reationCount的值,一开始我比较蒙的是,autorealse到底在啥时候会对name进行一次release操作,然后想了下,要进行release操作,肯定是要这个RunLoop进入休眠时,而在这样一个状态,RunLoop并未进入休眠......

实际上也证明我是正确的:Autorelease实际上只是把对release的调用延迟了,对于每一个Autorelease,系统只是把该Object放入了当 前的Autorelease pool中,当该pool被释放时,该pool中的所有Object会被调用Release。那么pool在啥时候被销毁?上面那个题目已经有解释了。

第十一、十二、十三道,貌似忘记了,不是送分题,但也没有很大难度的题,没啥印象了。

第十四、十五道,是算法题,第十四题,我没看懂出题人的意思?!看了好几遍,没看懂,唯一空白的一个题目。

第十五题,是将两个有序链表合并成一个有序链表,分分钟秒了它。

第一面,应该是iOS负责人。

大概聊了将近两个小时吧,挺认真负责的,技术非常好。他所提的比较有印象的面试问题:

1、RunLoop,于是我便把我理解的RunLoop详细说了说,大致就是下面这些东西:

RunLoop:运行循环,一个iOS程序的从main函数进入UIApplicationMain,UIApplicationMain就开启了一个RunLoop,这个RunLoop是主线程的RunLoop,也就是Main RunLoop,它的作用是让我们的OC程序一直运行。

实际上,我们可以把RunLoop认为是一个死循环,它在这个循环内,不断的休眠与重启,从而保持程序的运行,处理程序的各种事件。例如:

do
{
}while(1);

iOS中有两套API来使用和访问RunLoop,一个是Foundation下的NSRunLoop,一个是Core Foundation下的CFRunLoopRef,(NSRunLoop是基于CFRunLoopRef的一层OC包装)。

RunLoop与线程的关系:
每一个线程都有与之相对应的RunLoop,只有主线程的RunLoop是默认开启的,子线程的RunLoop需要我们手动开启。
RunLoop在第一次获取时创建,在线程结束时销毁。

[NSRunLoop CurrentRunLoop]

[NSRunLoop MainRunLoop]

CFRunLoopGetCurrent()
CFRunLoopGetMain()

Core Foundation中runLoop相关的五个类

CFRunLoopModeRef:
代表着RunLoop的运行模式,RunLoop在一个时间点只能运行一种模式,比如说要么是defaultMode,要么是TrackingMode

一个RunLoop包含若干个Mode,每个mode又包含若干个Source\Timer\observer

如果需要切换Mode,只能是先退出Loop,再重新指定一个Mode进入

这样做的目的主要是为了分割开不同组的Source/Timer/Observe,让他们互不影响。

CFRunLoopSourceRef :系统的一些点击、拖拽等事件,相当于一个事件源

CFRunLoopTimerRef : 定时器相关的处理

CFRunLoopObserverRef : 实际上,我们是可以监听RunLoop的活动的,比如说监听它是否开启、是否将要进入休眠等。

这两种RunLoop使我们在日常编程中经常用到的:
kCFRunLoopDefaultMode:App的默认Mode,通常主线程是在这个Mode下运行

UITrackingRunLoopMode:界面跟踪 Mode,用于 ScrollView 追踪触摸滑动,保证界面滑动时不受其他 Mode 影响

在OC中,几种常见的Mode
NSDefaultRunLoopMode 

UITrackingRunloopMode : 需要注意,这种模式下的Mode,是只能处理UIScrollView、或者继承自UIScrollView的对象的拖拽等事件的,也就是说,当UIScrollView在滚动的时候,是进入UITrackingRunloopMode,在默认条件下,Timer是添加在NSDefaultRunLoopMode下的,所以就不能处理Timer的相关事件。

(利用这样的一个特性,我们可以优化UITableView和UICollectionView的滚动,我们可以将图片的加载设置在NSDefaultRunLoop下,这样在滚动UITableView的时候,RunLoop会是UITrackingRunloopMode,就不会去加载图片,从而减少卡顿的现象出现,使得UI交互更加流畅)

还有一个NSRunLoopCommonMode,需要注意的是,它并不是真正的Mode,只是一个占位符

如果想要监听RunLoop状态的改变,有如下代码可以设置监听:
- (void)observer
{
    //创建observer
    CFRunLoopObserverRef observer = CFRunLoopObserverCreateWithHandler(CFAllocatorGetDefault(), kCFRunLoopAllActivities, YES, 0, ^(CFRunLoopObserverRef observer, CFRunLoopActivity activity) {
        NSLog(@"监听到RunLoop状态发生改变 %zd", activity);
    });

    //添加监听者
    CFRunLoopAddObserver(CFRunLoopGetCurrent(), observer, kCFRunLoopDefaultMode);

    CFRelease(observer);
}

这是runLoop可以被监听的状态:
/* Run Loop Observer Activities */
typedef CF_OPTIONS(CFOptionFlags, CFRunLoopActivity) {
    kCFRunLoopEntry = (1UL << 0),        //进入,也就是开启runloop了的时候
    kCFRunLoopBeforeTimers = (1UL << 1), //在处理所有定时器操作之前
    kCFRunLoopBeforeSources = (1UL << 2), //在处理所有source源(点击等事件)之前
    kCFRunLoopBeforeWaiting = (1UL << 5), //将要进入休眠状态
    kCFRunLoopAfterWaiting = (1UL << 6),  //将要苏醒的状态
    kCFRunLoopExit = (1UL << 7),         //退出runLoop
    kCFRunLoopAllActivities = 0x0FFFFFFFU   //以上所有的状态
};

@autoReleasePool在什么时候被释放?
它是在它所在的runLoop进入休眠时被释放,在runLoop再一次启动时创建。

当然,这些都是理论上的知识,实际中我们可以把imageView设置成在RunLoop的DefaultMode下显示,那么当UIScrollView,以及继承自UIScrollView的控件在拖拽的时候就不会显示ImageView,因为在滚动的时候,RunLoop是TrackingMode。

还可以开启一条常驻线程,这样就没必要多次创建子线程,造成性能上的损耗。

2、如果我们在开发中使用SDWebImage框架,会发现在UITableView滚动的停止的时候,它是优先下载显示在屏幕上的cell里面的图片的,这个效果如果让你来实现,你如何实现?

开发中我是经常使用SDWebImage框架的,但是没看过它的源代码,不过以前我做过不依赖SDWebImage框架的图片下载操作,那个时候是用NSOperation来实现的,还考虑到了重复下载的问题。

NSOperation是可以设置停止(暂停)的,这样的话,监听scrollView的滚动,当cell离开屏幕时,我们就把它设置为暂停下载状态,当它出现在屏幕时,再设置为开启下载状态。

面试官问我,是否还有其他的解决方案,(一脸蒙--)没有了。然后他提出了一种很好的解决方案,就是我们在设置并行队列的时候,是有一个优先值的,我们设置后面的image下载操作的优先级递增,这样的话,轻轻松松就解决了问题。

(好吧,我一直都在使用着默认的优先级,的确没考虑过这个问题,不过苹果文档也说了,建议开发者使用default优先级,因为如果优先级比较乱的话,可能会造成未知原因而导致程序崩溃,但这并不是理由,不知道就是不知道)。

3、问了下iOS里面工厂模式的使用场景,其实这个问题我在《Objective-C编程之道》上看到过,也知道它,但是那一瞬就是脑海一片空白,好吧,然后面试官和我说了,比如UIButton的类方法创建,里面是黑箱的,我们只是知道它会返回一个啥样类型button回来,类似的,NSValues等。(不得不说是幸运啊,刚好这个问题,在移动端负责人面我时候,我就举了这样的例子)

4、有三个网络请求需要发送,等三个网络请求发送完之后,要更新UI,怎么操作可以节省时间?

我第一个回答,觉得是直接使用dispatch_group来搞就好,不过面试官提醒了下我,就是一个网络请求发送完毕之后,等待数据返回还要一段时间,所以,dispatch_group是不行的。

然后,我觉得貌似只能一条条发送了,认真的想了下,其实是可以设置一个int属性,来记录是否都返回数据成功了,如果成功,就++,然后用kvo来监听这个属性就好。(当时回答是这么回答的,实际上应该用不到kvo来监听,可以直接重写该属性的setter方法)

还有其他的问题吧,不过印象不是很深刻了。

移动端负责人面试:

1、至此,第一面算是过了,心中松了一口气。这位面试官进来,先是问了我,iOS程序启动这之间的一系列过程,我回答的比较简单,从main->UIApplicationMain来开启一个主运行循环->Main RunLoop 开始处理各种source\observe\timer,从一个Mode到另一个Mode,然后调用appDelegate里面的application didFinish....那方法,进入KeyWindow......

2、把你所知道的设计模式其中思想都说说,举例说下应用场景

差点跪了,以前在看设计模式的时候,那理论太多了,记不住啊。然后只说出九种模式的思想,勉强算是过关了。

3、把所知道的排序算法手写出来

我在想,还好不是面试官来定某些算法,我所知道的并且能写的,冒泡、选择、快速、归并,写了下,算是过关了。

技术总监\经历面试

就是一个算法题,一个人上台阶,一次可以走一阶,走两阶,走三阶,那么如果有n阶,走法有多少种?

递推题,根据前面的规律,可以很容易推出,f(n) = f(n-1) + f(n-2) +f(n-3),然后用c语言把它写出来了。

之后就是人事面,顺利拿到offer。

ps:我辞职报告已经提交了,公司让我帮他面试iOS人员,我想说,那些培训的,写两年iOS工作经验,竟然和我说没学过C?对C不熟?作为一个计算机专业毕业的人,做数据结构的题,20道只正确7道,我去。这一行现在是有多乱,开的工资,10~~15k,还有一个15~~25k!真的是无知者无畏么?

论一次iOS面试的更多相关文章

  1. ios面试技术要点

    iOS面试 技术总结点(可参考):多线程 运行时 runloop app框架 几种动画编程 jsonmodel原理 sdwebimage原理 masonry怎么应用及原理 应用框架有哪些 说一下Fac ...

  2. iOS 面试基础题目

    转载: iOS 面试基础题目 题目来自博客:面试百度的记录,有些问题我能回答一下,不能回答的或有更好的回答我放个相关链接供参考. 1面 Objective C runtime library:Obje ...

  3. iOS面试贴士

    iOS面试小贴士 ———————————————回答好下面的足够了------------------------------------- 多线程.特别是NSOperation 和 GCD 的内部原 ...

  4. IOS面试攻略

    IOS面试攻略(1.0) 2013-10-13 20:58:09|  分类: IOS面试 |  标签:ios知识点总汇  ios面试  |举报|字号 订阅     来自:伊甸网 @ 看到这个关键字,我 ...

  5. C C++ OC iOS面试重点问题(一)

    C C++ OC iOS面试重点问题(一) 1.字符串常量需要加\0 2.逻辑运算 位操作(经典:实现两个数的交换) 3.关键字 4.引用和指针的区别和联系 5.如何引用一个已经定义过的全局变量?  ...

  6. IOS面试问题总结

    IOS面试问题总结 分类: IOS开发2013-11-20 17:26 10458人阅读 评论(1) 收藏 举报   目录(?)[+]   通过网络搜寻和自己总结经历找了一些IOS面试经常被问道的问题 ...

  7. 十个iOS面试问题

    十个iOS面试问题 十个iOS面试问题.不管对于招聘和应聘来说,面试都是很重要的一个环节,特别对于开发者来说,面试中的技术问题环节不仅是企业对应聘者技能和积累的考察,也是一个开发者自我检验的好机会. ...

  8. [转] 上级向的十个iOS面试问题

    上级向的十个iOS面试问题 转自 http://onevcat.com/2013/04/ios-interview/ 不管对于招聘和应聘来说,面试都是很重要的一个环节,特别对于开发者来说,面试中的技术 ...

  9. iOS面试的算法相关

    转自:https://www.jianshu.com/p/c4820b159159 面试中遇到的这些算法,在平常工作中,基本不会用到. 不过现实的面试中经常喜欢问关于算法的问题 有些还要求写出代码.一 ...

  10. 一些iOS面试基础题总结

    一些iOS面试基础题总结 目录 多线程 AutoLayout objc_msgSend Runtime 消息转发 Category NSObject 与 objc_class Runloop Auto ...

随机推荐

  1. 阿里云中Centos下配置防火墙

    一.检查iptables服务状态 [root@woxplife ~]# service iptables status iptables: Firewall is not running. 说明ipt ...

  2. 检查密码复杂度的C#正则表达式

    在用户注册与修改.重置密码时,强制密码达到一定的复杂度,是减少盗号的有效措施之一. 而在代码中检查密码复杂度就需要用到正则表达式,比如要求密码必须包含数字.小写或大写字母.特殊字符.字符数在8-30之 ...

  3. .net 获取当前周及根据年和周获取起始结束时间

    获取当前日期周数 int str = new System.Globalization.GregorianCalendar().GetWeekOfYear(System.DateTime.Now, S ...

  4. Hash哈希(二)一致性Hash(C++实现)

    一致性Hash 一致性哈希算法在1997年由麻省理工学院提出的一种分布式哈希(DHT)实现算法,设计目标是为了解决因特网中的热点(Hot spot)问题,经常用于分布式.负载均衡等. 原理 一致哈希是 ...

  5. [芯片][MPU6050] MPU60X0的DMP相关链接

    标题:发个自己做的UD分解+强跟踪卡尔曼滤波做的双轴姿态测量 链接:http://www.amobbs.com/thread-5511854-1-1.html 关键词:UD分解+强跟踪卡尔曼滤波,采用 ...

  6. [Java Web] 2、Web开发中的一些架构

    1.企业开发架构: 企业平台开发大量采用B/S开发模式,不管采用何种动态Web实现手段,其操作形式都是一样的,其核心操作的大部分都是围绕着数据库进行的.但是如果使用编程语言进行数据库开发,要涉及很多诸 ...

  7. jpa 注解使用说明

    1.@Entity(name="EntityName") 必须,name为可选,对应数据库中一的个表 2.@Table(name="",catalog=&quo ...

  8. jQuery的XX如何实现?——2.show与链式调用

    往期回顾: jQuery的XX如何实现?——1.框架 -------------------------- 源码链接:内附实例代码 jQuery使用许久了,但是有一些API的实现实在想不通.于是抽空看 ...

  9. SQL语法的重要知识点总结

    好几年没写SQL语句了.现在到了新的team,需要用到数据库.作为QA的话时常需要使用客户端工具连接到数据库中找寻或修改数据.这么长时间没使用,一些SQL的使用技巧都忘得差不多了.晚上看了一些资料,花 ...

  10. 深入浅出OOP(三): 多态和继承(动态绑定/运行时多态)

    在前面的文章中,我们介绍了编译期多态.params关键字.实例化.base关键字等.本节我们来关注另外一种多态:运行时多态, 运行时多态也叫迟绑定. 运行时多态或迟绑定.动态绑定 在C#语音中,运行时 ...