iOS面试题
前提:上周同事去一家初创型互联网公司去面试iOS开发遇到如下的面试题,也跟我分享了一下具体面试内容,写篇博客总结一下。
面试题如下
- 极光推送使用
- 谈谈对高德地图的使用
- 项目中使用过阿里云的即时通讯,是否使用过非第三方的即时通讯
- 谈谈高并发编程
- 你理解的多线程
- 介绍APP启动过程,如果启动比较耗时是否有优化的方法
- 简单说说TCP和UDP的理解
- 说下MD5 base64以及AES加密,以及如何防止反编译
- 说一下了解的设计模式,以及架构设计
- 项目中的角色权限和分配,是否做过单点登录
- 有没有处理过万以上的数据实时传输,如何处理
- 是否有自己的博客和开源,或者谈谈对于常用框架的理解
看到具体的面试题后,我总结了一下如下分四个部分:
1.第一部分的是对常规SDK的使用和项目中常用框架。
- 友盟、极光、支付宝/微信、高德。
- 登录、分享,通知,支付,地图
友盟
极光
支付宝、微信
高德地图
- AFNetworking、SDWebImage、Masonry、MJExtension
- 网络请求,图片加载,布局,转模型解析
AFNetworking
SDWebImage
Masonry
MJExtension
2.第二部分的是对概念设计模式的理解。
高并发编程
围绕高并发的核心词 :
Grand Central Dispatch(简称GCD)、NSOperation、NSThread
、Operation Queues(运行队列)
、多线程
- GCD:
GCD
属于Apple开发的线程管理,是最常使用的并发编程方式。其核心思想是将并发执行的任务封装到Block
回调中,在把Block
分发到不同类型的队列里,对不同类型的队列,实现并发执行。GCD
以dispatch_async
开头是一套C函数的调用方法:
//dispatch_async:异步执行
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(<#time#> * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
<#do something#> // 待执行的任务
});
- NSOperation:
NSOperation
的核心是对GCD
的一种封装,把需要并发执行的任务封装到NSOperation
中,然后添加到NSOperationQueue
并发执行。调用start
方法即可开始执行操作,调用cancel
方法中途取消操作,completionBlock
处理完的回调。
- NSThread:
GCD
的清量易用一定意义上替代诸NSThread
这种较为复杂技术高效的技术。每一个NSThread
都是一个线程。selector:
线程执行的方法,该selector
只能有一个参数,而且返回值是void
。target:selector
消息发送的对象argument:
传递给target
的唯一参数,可以为nil
。NSThread
的开启,关闭以及一些执行状态控制都需要开发者自己管理 detachNewThreadSelector:toTarget:withObject:
initWithTarget:selector:object:
两者区别在于下面获取到了NSThread
对象方便终止线程。
[NSThread detachNewThreadSelector:@selector(loadData) toTarget:self withObject:nil];
#pragma mark - 加载耗时数据
- (void)loadData
{
//并发执行执行任务
}
NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(loadData) object:nil];
[thread start]; //调用
总结:如果选择的话我更倾向于
GCD
,GCD
是一个轻量级别的级别,底层实现影藏的技术,通过其和Block
相结合可以轻松实现多线程编程。
你理解的多线程
- 多线程的原理
同一时间,CPU只能处理1条线程,只有1条线程在工作(执行) 多线程并发(同时)执行,其实是CPU快速地在多条线程之间调度(切换) 如果CPU调度线程的时间足够快,就造成了多线程并发执行的假象 思考:如果线程非常非常多,会发生什么情况?
CPU会在N多线程之间调度,CPU会累死,消耗大量的CPU资源 每条线程被调度执行的频次会降低(线程的执行效率降低)
- 多线程的优点
能适当提高程序的执行效率 能适当提高资源利用率(CPU、内存利用率)
- 多线程的缺点
开启线程需要占用一定的内存空间(默认情况下,主线程占用1M,子线程占用 512KB),如果开启大量的线程,会占用大量的内存空间,降低程序的性能
线程越多,CPU在调度线程上的开销就越大 程序设计更加复杂:比如线程之间的通信、多线程的数据共享
简单说说TCP和UDP的理解
这两个工作在TCP/IP协议传输层的两个不同的协议,是用来传输数据用的。
TCP:(Transmission Control Protocol)和UDP(User Datagram Protocol)属于传输层协议。这是一个全双工的、面向连接的、可靠的并且是精确控制的协议。
- 主要应用在那些实用性不强,但要求不能出错的地方。比如网页浏览,文件下载,文件收发。
UDP:(User Datagram protocol)是面向数据报的运输层协议。是一个不可靠的传输协议。
- 不关心传输数据段到达的目的方的顺序,所以不可靠。开销比
TCP
小很多。比如及时通讯,视频,语音。
两者的区别和联系:
区别:TCP是面向连接的可靠的传输控制协议,UDP是面向非连接的用户数据协议。
联系:TCP(三次握手保证相对可靠性)可传大量数据,速度相对比较慢,UDP一次性传输少量对可靠性要求不高的数据,速度比较快
tcp一般用于音频、视频等数据的传输,资源能耗比较小,对可靠性要求不高,即使丢失一两条数据也不会产生太大影响。
什么是“三次握手”:
三次握手是指建立一个TCP连接时,需要客户端和服务器总共发送3个包。三次握手的目的是连接服务器指定端口,建立TCP连接,并同步连接双方的序列号和确认号并交换 TCP 信息。
介绍APP启动过程,如果启动比较耗时是否有优化的方法
APP启动过程
1. 解析Info.plist
- 加载相关信息,如闪屏
- 沙箱建立,权限检查
2. Mach-O加载
- 如果是胖二进制,寻找合适CUP类别的部分
- 加载所有依赖Mach-O文件
- 定位内部,外部指针引用,如字符串,函数
- 执行声明函数
- 加载扩展类
- C++静态对象加载,调用Objc的+(load)函数
3. 程序执行
- main函数
- 执行UIApplicationMain函数
- UIApplicationDelegate对象开始处理监听事件
APP启动缓慢,想到的因素
- main( ) 函数内有耗时操作
- 动态库加载太多
rootViewControlle
以及childViewController
的加载,view
和subViews
的加载耗时
优化
- 移除不需要用到的动态库
- 移除不需要用到的类
- 合并功能类似的类和扩展(Category)
- 压缩图片资源
- 优化
applicationWillFinishLaunching
- 优化
rootViewController
加载
设计模式
MVC:
MVC(Model View Controller):模型(model)-视图(view)-控制器(controller)
- M(Model):实际上考虑的是什么的问题,你程序本质上是什么,独立于
UI
工作,是程序中用于处理应用逻辑的部分,通常赋值存取数据。 - C(Controller):控制你的数据(Model)如何显示在屏幕上,他需要数据的时候会告诉Model,你帮我获取数据,当他需要如何展示界面的时候和更新界面的时候他告诉V(View),是V和M之间的沟通桥梁。
- V(View):是
Controller
的使用类,用于构建视图。通常根据Model
来创建。
MVC的优点
- 低耦合性
视图层和业务层分离,这样就允许更改视图层代码而不用重新编译模型和控制器代码,同样,一个应用的业务流程或者业务规则的改变只需要改动MVC的模型层即可。因为模型与控制器和视图相分离,所以很容易改变应用程序的数据层和业务规则。
- 高重用性和可适用性
由于模型返回的数据没有进行格式化,所以同样的构件能被不同的界面使用。例如,很多数据可能用HTML来表示,但是也有可能用WAP来表示,而这些表示所需要的命令是改变视图层的实现方式,而控制层和模型层无需做任何改变。
- 较低的生命周期成本
MVC使开发和维护用户接口的技术含量降低。
- 可维护性
分离视图层和业务逻辑层也使得应用更易于维护和修改。
总结优点:提高代码的可读性和可移植性,降低耦合度,提高内聚,大大提高开发的效率。
MVC的缺点:
MVC对于一些接单的界面额外的增加复杂性,视图与控制器间的过于紧密的连接。不适合中小型APP的开发,会额外增加开发成本。
V向C发消息:
- target-action:C会在自己的内部“悬挂”一个目标(target),可能屏幕上是一个按钮,当按钮被点击时,
action
就会被发送给与之对应的target
,这样V和C就有了交流。 - delegate(代理):
delegate
在上图中是黄色的箭头,C把自己设置为V的委托(delegate),它让V知道,如果该显示什么,就给C发delegate
消息。 - datasource(数据源):当V需要显示数据的时候,他将需要别人的帮助将数据传递给他,这就是数据源了。
- Notification & KVO:一种类似电台的方法,Model信息改变时会广播消息给感兴趣的人。
架构设计:
建议可以从以下几个方面回答
- 网络层的设计方案
- 本地持久化方案
-
View
层组织和调用方案
APP好的架构的评判标准
- 代码整齐,分类明确
- 易扩展,方便测试
- 没有横向依赖,不到万不得已没有跨层访问
- 接口少,统一,参数少
- 高性能
- 思路与方法上统一保持一致
说下MD5 base64以及AES加密
MD5:Message Digest Algorithm 5
MD5
是iOS中比较常见的加密方法之一,其特点有一下几点
-
加密的不可逆性,只能够加密,不能够解密。
-
明文加密后长度都是固定的,长度为16进制32位。
-
AES加解密:相较于DES和3DES算法而言,AES算法有着更高的速度和资源使用效率,安全级别也较之更高了。
-
AES使用的是对称加密.所谓对称加密就是加解密双方使用的密钥相同.因此通过一种保密的方法让客户端与服务器拥有该密钥,即可成功使用加解密。
base64加密:使用64个字符来对任意数据进行编码。
- base64加密:
base64EncodedStringWithOptions
- base64解密:
initWithBase64EncodedString
如何防止反编译
- 本地数据加密:对
NSUserDefaults
和sqlite
等本地存储数据加密 - URL编码加密:对程序中出现的
URL
进行加密,防止URL
被静态分析 - 网络传输加密:有效的防止数据接口拦截
- 程序结构混排加密:把应用程序的逻辑打乱,将可读性降到最低。
3.第三部分的是对项目中具体某个功能点的实现。
角色权限和分配,是否做过单点登录
在处理这类问题的时候,角色权限和分配对后台的依赖比较大。拿单点登录来说:单点登录SSO(Single Sign On)是目前比较流行的企业业务整合的解决方案之一。SSO的定义是在多个应用系统中,用户只需要登录一次就可以访问所有相互信任的应用系统。简单来说单点登录核心就是要解决,验证信任机制的有效性即存储信任和验证信任。如下优缺点和三种实现方式
单点登录优点
- 提高用户的效率。
- 提高开发人员的效率。
- 简化管理。
单点登录缺点
- 不利于重构
- 无人看守桌面
1.以Cookie作为凭证媒介
Cookie凭借最简单的单点登录实现方式,是使用cookie作为媒介,存放用户凭证。
用户登录父应用之后,应用返回一个加密的cookie,当用户访问子应用的时候,携带上这个cookie,授权应用解密cookie并进行校验,校验通过则登录当前用户。
以上通过Cookie的方式实现单点登录很容易发现弊端
- Cookie不安全
- 以及不能跨域
第一个
Cookie
不安全上我们可以通过加密等方式来避免泄露,但第二天跨域是硬伤。
2.通过JSONP实现
JSONP相比较Cookie的方法,JSONP更好的在于解决了跨域问题,我们父应用在登录成功后把Session匹配的Cookie会存到应用中。当用户需要登录子应用的时候,授权应用访问父应用提供的JSONP接口,并在请求中带上父应用域名下的Cookie,父应用接收到请求,验证用户的登录状态,返回加密的信息,子应用通过解析返回来的加密信息来验证用户。
虽然解决了跨域但是还是存在上一个方法一样的弊端,就是信任机制的不安全性,易泄露。
3.通过页面重定向的方式
页面重定向通过父应用和子应用来回重定向中进行通信,解决信任机制的不安全性,实现信息的安全传递。
父类提供一个登录接口,用户通过子应用登录连接访问这个接口,判断如果用户还未登录,则返回登录界面输入账号密码登录。如以及登录则声称密码Token,验证Token的接口,检验后是否登录成功。
这个方法固然解决了跨域和安全两个问题,但是相比较上两种而言增加了登录的复杂度。
参考:单点登录的三种实现方式
4.博客,开源。
开源的话,推荐
GitHub
- github地址:RocketsChen欢迎
Star
和Follow
坚持开源写博客,对技术的提升还是很有帮助的,如果把平常项目开发中小技巧和问题记录下来,长期积累下去也是一件有意义的事。