iOS面试旗开得胜之横扫千军篇(三)
本文问题来自iOS面试旗开得胜之问题篇 中的横扫千军之战胜篇
7.AFNetworking你使用过是哪几个版本?他们有什么区别?使用过程中应该注意哪些问题?
AFNetworking支持HTTP请求和基于REST的网络服务(包括GET、POST、 PUT以及DELETE等),支持ARC。AFNetworking项目中还包含一些列单元测试。
AFNetworking 2.0开始使用NSURLConnection的基础API ,以及较新基于NSURLSession的API的选项。
AFNetworking 3.0现已完全基于NSURLSession的API,删除了了对 NSURLConnection的封装内容
这是因为NSURLSession能够完全替代NSURLConnection,并且具有很多优点:
- 支持后台运行的网络任务
- 暂停、停止、重启网络任务,不需要自己封装NSOperation
- 支持断点续传,异步下载
- 支持上传,异步上传
- 获取下载、上传的进度
注意:
3.0版本最低支持版本是从iOS7
废弃的类
废弃对NSURLConnection的支持 被删除的类: - AFURLConnectionOperation - AFHTTPRequestOperation - AFHTTPRequestOperationManager 用以替代的是下面的类: - AFURLSessionManager - AFHTTPSessionManager 进行修改的类: - UIImageView+AFNetworking - UIWebView+AFNetworking.h - UIButton+AFNetworking.h
如果你之前的开发是基于AFHTTPRequestOperationManager的网络请求现在你应该转到AFHTTPSessionManager下去进行.
UIKit的迁移
图片下载已经被重构,以遵循AlamofireImage架构与新的AFImageDownloader类。这个类的图片下载职责的代理人是UIButton与UIImageView的类目,并且提供了一些方法,在必要时可以自定义。类别中,下载远程图片的实际方法没有改变。
UIWebView的类目被重构为使用AFHTTPSessionManager作为其网络请求。
UIAlertView的类目被废弃
从AFNetworking 3.0后UIAlertView的类目因过时而被废弃。并没有提供UIAlertController类目的计划,因为这是应用程序应处理的逻辑,而不是这个库。
下面进行新旧对比:
AFNetwork 2.x
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
//设置网络请求超时时间
[manager.requestSerializer willChangeValueForKey:@"timeoutInterval"];
manager.requestSerializer.timeoutInterval = 30.0f;
[manager.requestSerializer didChangeValueForKey:@"timeoutInterval"];
[manager.requestSerializer setValue:@"application/x-www-form-urlencoded;" forHTTPHeaderField:@"Content-Type"];
[self addHeaderParams:manager];
manager.responseSerializer.acceptableContentTypes = [NSSet setWithObjects:@"application/json",@"text/html",nil];
[manager POST:self.requestURL
parameters:self.requestParams
success:^(AFHTTPRequestOperation *operation, id responseObject) {
(@"success-POST:%@",responseObject);
}
failure:^(AFHTTPRequestOperation *operation, NSError *error) {
DebugLog(@"failurePOST:%@",error.description)
}];
AFNetworking 3.x
AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
[manager.requestSerializer willChangeValueForKey:@"timeoutInterval"];
manager.requestSerializer.timeoutInterval = 30.0f;//30.0f
[manager.requestSerializer didChangeValueForKey:@"timeoutInterval"];
[manager.requestSerializer setValue:@"application/x-www-form-urlencoded;" forHTTPHeaderField:@"Content-Type"];
[self addHeaderParams:manager];
manager.responseSerializer.acceptableContentTypes = [NSSet setWithObjects:@"application/json",@"text/html",nil];
[manager POST:self.requestURL parameters:self.requestParams progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {
NSLog(@"success-POST:%@",responseObject);
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
}];
即:每次开启一个网络请求时,首先新建一个AFHTTPSessionManager,然后将相关的requestSerializer和reponseSerializer赋值;最后发起相应的GET/POST等请求。 如果是直接采用NSURLSession来请求网络,写法如下:
NSURLSession *session = [NSURLSession
sessionWithConfiguration:
[NSURLSessionConfiguration defaultSessionConfiguration]
delegate:nil
delegateQueue:[NSOperationQueue mainQueue]];
NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request
completionHandler:completionHandler];
[dataTask resume];
即:新建一个Session(多个请求要用共享的SessionManager/Session),然后新建task,激活task,完成网络请求。
共享原因:
共享的Session将会复用TCP的连接,而每次都新建Session的操作将导致每次的网络请求都开启一个TCP的三次握手,共享会提升网络速度 AFNetworking 3.x 提供的post方法:
[manager POST: parameters: constructingBodyWithBlock: progress: success: failure:]
[manager POST: parameters: progress: success: failure:]
不建议使用的方法:
[manager POST: parameters: success: failure:];
[manager POST: parameters: constructingBodyWithBlock: success: failure:]
AFNetworking缓存
AFNetworking实际上使用了两个独立的缓存机制:
(1)AFImagecache:一个提供图片内存缓存的类,2.x时继承自NSCache,3.x不再使用NSCache。AFImagecache3.x之前存在于UIImageView+AFNetwork,之后存在于AFAutoPurgingImageCache中。
(2)NSURLCache:仍使用原生缓存机制:NSURLCache。NSURLConnection’s默认的URL缓存机制,用于存储NSURLResponse对象:一个默认缓存在内存,通过配置可以缓存到磁盘的类。NSURLCache对每个NSURLRequest对象都会遵守缓存策略(NSURLRequestCachePolicy)。
注意:NSCache与NSURLCache没有任何关系
3.0之前的缓存方法:存在于AFURLConnectionOperation类文件中。
- (void)setCacheResponseBlock:(NSCachedURLResponse * (^)(NSURLConnection *connection, NSCachedURLResponse *cachedResponse))block;
3.0之后:在类AFURLSessionManager中
- (void)setDataTaskWillCacheResponseBlock:(nullable NSCachedURLResponse * (^)(NSURLSession *session, NSURLSessionDataTask *dataTask, NSCachedURLResponse *proposedResponse))block;
苹果系统缓存存储策略:
{
NSURLCacheStorageAllowed, //默认,可以存在内存(重启设备清除),可以存储磁盘(代码清除)
NSURLCacheStorageAllowedInMemoryOnly,
NSURLCacheStorageNotAllowed,
} NSURLCacheStoragePolicy;
请求缓存策略:
{
NSURLRequestUseProtocolCachePolicy = 0, //默认策略
NSURLRequestReloadIgnoringLocalCacheData = 1,//忽略本地缓存,从源加载
NSURLRequestReloadIgnoringLocalAndRemoteCacheData = 4, // 忽略本地&服务器缓存,从源加载
NSURLRequestReloadIgnoringCacheData = NSURLRequestReloadIgnoringLocalCacheData,
NSURLRequestReturnCacheDataElseLoad = 2, //先从缓存加载,如果没有缓存,从源加载
NSURLRequestReturnCacheDataDontLoad = 3, //离线模式,加载缓存数据(无论是否过期),不从源加载
NSURLRequestReloadRevalidatingCacheData = 5 // 存在的缓存数据先确认有效性,无效的话从源加载
};
typedef NSUInteger NSURLRequestCachePolicy;
清除所有的URL缓存Response:
[[NSURLCache sharedURLCache] removeAllCachedResponses];
8.谈谈你对算法的理解,在工作中你都应用了哪些算法来解决问题
基础算法
快速排序算法
快速排序是由东尼·霍尔所发展的一种排序算法。在平均状况下,排序 n 个项目要Ο(n log n)次比较。在最坏状况下则需要Ο(n2)次比较,但这种状况并不常见。事实上,快速排序通常明显比其他Ο(n log n) 算法更快,因为它的内部循环(inner loop)可以在大部分的架构上很有效率地被实现出来。
快速排序使用分治法(Divide and conquer)策略来把一个串行(list)分为两个子串行(sub-lists)。
算法步骤:
1 从数列中挑出一个元素,称为 “基准”(pivot),
2 重新排序数列,所有元素比基准值小的摆放在基准前面,所有元素比基准值大的摆在基准的后面(相同的数可以到任一边)。在这个分区退出之后,该基准就处于数列的中间位置。这个称为分区(partition)操作。
3 递归地(recursive)把小于基准值元素的子数列和大于基准值元素的子数列排序。
递归的最底部情形,是数列的大小是零或一,也就是永远都已经被排序好了。虽然一直递归下去,但是这个算法总会退出,因为在每次的迭代(iteration)中,它至少会把一个元素摆到它最后的位置去。
堆排序算法
堆排序(Heapsort)是指利用堆这种数据结构所设计的一种排序算法。堆积是一个近似完全二叉树的结构,并同时满足堆积的性质:即子结点的键值或索引总是小于(或者大于)它的父节点。
堆排序的平均时间复杂度为Ο(nlogn) 。
算法步骤:
1.创建一个堆H[0..n-1]
2.把堆首(最大值)和堆尾互换
3. 把堆的尺寸缩小1,并调用shift_down(0),目的是把新的数组顶端数据调整到相应位置
4. 重复步骤2,直到堆的尺寸为1
归并排序
归并排序(Merge sort,台湾译作:合并排序)是建立在归并操作上的一种有效的排序算法。该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。
算法步骤:
1. 申请空间,使其大小为两个已经排序序列之和,该空间用来存放合并后的序列
2. 设定两个指针,最初位置分别为两个已经排序序列的起始位置
3. 比较两个指针所指向的元素,选择相对小的元素放入到合并空间,并移动指针到下一位置
4. 重复步骤3直到某一指针达到序列尾
5. 将另一序列剩下的所有元素直接复制到合并序列尾
二分查找算法
二分查找算法是一种在有序数组中查找某一特定元素的搜索算法。搜素过程从数组的中间元素开始,如果中间元素正好是要查找的元素,则搜素过程结束;如果某一特定元素大于或者小于中间元素,则在数组大于或小于中间元素的那一半中查找,而且跟开始一样从中间元素开始比较。如果在某一步骤数组为空,则代表找不到。这种搜索算法每一次比较都使搜索范围缩小一半。折半搜索每次把搜索区域减少一半,时间复杂度为Ο(logn) 。
加密算法原理
MD5加密
MD5加密是最常用的加密方法之一,是从一段字符串中通过相应特征生成一段32位的数字字母混合码。
MD5主要特点是 不可逆,相同数据的MD5值肯定一样,不同数据的MD5值不一样(也不是绝对的,但基本是不能一样的)。MD5算法还具有以下性质:
1、压缩性:任意长度的数据,算出的MD5值长度都是固定的。
2、容易计算:从原数据计算出MD5值很容易。
3、抗修改性:对原数据进行任何改动,哪怕只修改1个字节,所得到的MD5值都有很大区别。
4、弱抗碰撞:已知原数据和其MD5值,想找到一个具有相同MD5值的数据(即伪造数据)是非常困难的。
5、强抗碰撞:想找到两个不同的数据,使它们具有相同的MD5值,是非常困难的。
MD5虽然说是不可逆的,但是由于有网站http://www.cmd5.com的存在,专门用来查询MD5码 所以有的简单的MD5码是可以在这里搜到源码的。为了让MD5码更加安全 涌现了很多其他方法 如加盐。 盐要足够长足够乱 得到的MD5码就很难查到。
SHA1加密
安全哈希算法(Secure Hash Algorithm)主要适用于数字签名标准(Digital Signature Standard DSS)里面定义的数字签名算法(Digital Signature Algorithm DSA)。对于长度小于2^64位的消息,SHA1会产生一个160位的消息摘要。当接收到消息的时候,这个消息摘要可以用来验证数据的完整性。在传输的过程中,数据很可能会发生变化,那么这时候就会产生不同的消息摘要。 SHA1有如下特性:不可以从消息摘要中复原信息;两个不同的消息不会产生同样的消息摘要。
HMAC加密
此加密方法需要先生成密钥,然后再对密码进行MD5和HMAC加密,数据库中需要存放当时使用的密钥和密码加密后的密文,在用户登陆时 再次对填入的密码用密钥进行加密 并且还要加上当前时间(精确到分钟) 再次HMAC加密,服务器里也会拿出以前存放的密文加上时间再次加密。所以就算黑客在中途截取了密码的密文 也在能在1分钟只能破译才能有效,大大加强了安全性。服务器为了考虑到网络的延迟一般会多算一种答案,如23分过来的密码 他会把23分和22分的都算一下和用户匹配只要对上一个就允许登陆。
base64加密
在MIME格式的电子邮件中,base64可以用来将binary的字节序列数据编码成ASCII字符序列构成的文本。使用时,在传输编码方式中指定base64。使用的字符包括大小写字母各26个,加上10个数字,和加号“+”,斜杠“/”,一共64个字符,等号“=”用来作为后缀用途。 完整的base64定义可见RFC 1421和RFC 2045。编码后的数据比原始数据略长,为原来的4/3。
对称加密算法
优点:算法公开、计算量小、加密速度快、加密效率高、可逆
缺点:双方使用相同钥匙,安全性得不到保证
现状:对称加密的速度比公钥加密快很多,在很多场合都需要对称加密,相较于DES和3DES算法而言,AES算法有着更高的速度和资源使用效率,安全级别也较之更高了,被称为下一代加密标准
nECB :电子代码本,就是说每个块都是独立加密的nCBC :密码块链,使用一个密钥和一个初始化向量 (IV)对数据执行加密转换
ECB和CBC区别:CBC更加复杂更加安全,里面加入了8位的向量(8个0的话结果等于ECB)。在明文里面改一个字母,ECB密文对应的那一行会改变,CBC密文从那一行往后都会改变。
RSA加密
RSA非对称加密算法
非对称加密算法需要两个密钥:公开密钥(publickey)和私有密钥(privatekey)公开密钥与私有密钥是一对,如果用公开密钥对数据进行加密,只有用对应的私有密钥才能解密;如果用私有密钥对数据进行加密,那么只有用对应的公开密钥才能解密
特点:非对称密码体制的特点:算法强度复杂、安全性依赖于算法与密钥,但是由于其算法复杂,而使得加密解密速度没有对称加密解密的速度快,对称密码体制中只有一种密钥,并且是非公开的,如果要解密就得让对方知道密钥。所以保证其安全性就是保证密钥的安全,而非对称密钥体制有两种密钥,其中一个是公开的,这样就可以不需要像对称密码那样传输对方的密钥了
基本加密原理:
(1)找出两个“很大”的质数:P & Q
(2)N = P * Q
(3)M = (P – 1) * (Q – 1)
(4)找出整数E,E与M互质,即除了1之外,没有其他公约数
(5)找出整数D,使得E*D除以M余1,即 (E * D) % M = 1
经过上述准备工作之后,可以得到:E是公钥,负责加密D是私钥,负责解密N负责公钥和私钥之间的联系加密算法,假定对X进行加密(X ^ E) % N = Yn根据费尔马小定义,根据以下公式可以完成解密操作(Y ^ D) % N = X
但是RSA加密算法效率较差,对大型数据加密时间很长,一般用于小数据。常用场景:分部要给总部发一段报文,先对报文整个进行MD5得到一个报文摘要,再对这个报文摘要用公钥加密。然后把报文和这个RSA密文一起发过去。总部接收到报文之后要先确定报文是否在中途被人篡改,就先把这个密文用私钥解密得到报文摘要,再和整个报文MD5一下得到的报文摘要进行对比 如果一样就是没被改过。
9.谈谈你对React Native 、weex、Web、NativeAPP 和Hybrid APP 的看法
Native APP开发模式
- 这种模式指的是用原生 API 开发APP,就是说用Objective-C、swift 开发iOS。
- 优点:
- 用户体验最佳,优质的用户界面,华丽的交互。
- 不同平台提供不同体验。
- 节省带宽成本。
- 可访问本地资源,打开速度快。
- 缺点:
- 维护多个版本的成本比较高。
- 开发成本比较大。
- 盈利需要与第三方分成。
- AppStore 审核机制比较麻烦。
- 优点:
Web App(网页应用)
- 指使用Html开发的移动端网页App,类似微信小程序,整个App都是网页。
- 优点:
- 用户不需要安装,不会占用手机内存。
- 开发成本低,维护更新简单。
- 跨平台好。
- 缺点:
- 用户体验不好,不能离线,必须联网。
- 现在纯web的App 貌似不能上AppStore。
- 优点:
Hybrid APP
- 混合开发模式,原生Api+Html共同开发,比如iOS,用html写好界面,用UIWebView展示。
- 多 View 混合型 这种模式主要特点是将webview作为Native中的一个view组件,当需要的时候在独立运行显示,也就是说主体是Native,web技术只是起来一些补充作用.`这种模式几乎就是原生开发,没有降低什么难度,到了16年几乎已经没人使用了
- 单View混合型 这种模式是在同一个view内,同时包括Native view和webview(互相之间是层叠的关系),比如一些应用会用H5来加载百度地图作为整个页面的主体内容,然后再webview之上覆盖一些原生的view,比如搜索什么的.这种模式开发完成后体验较好,但是开发成本较大,一般适合一些原生人员使用
Web主体型
这种模式算是传统意义上的Hybrid开发,很多Hybrid框架都是基于这种模式的,比如PhoneGap,AppCan,Html5+等 这种模式的一个最大特点是,Hybrid框架已经提供各种api,打包工具,调试工具,然后实际开发时不会使用到任何原生技术,实际上只会使用H5和js来编写,然后js可以调用原生提供的api来实现一些拓展功能。往往程序从入口页面,到每一个功能都是h5和js完成的。 理论上来说,这种模式应该是最佳的一种模式(因为用H5和js编写最为快速,能够调用原生api,功能够完善),但是由于一些webview自身的限制,导致了这种模式在性能上损耗不小,包括在一些内存控制上的不足,所以导致体验要逊色于原生不少。 当然了,如果能解决体验差问题,这种模式应当是最优的(比如由于iOS对H5支持很好,iOS上的体验就很不错)。
多主体共存型(灵活型)
这种模式的存在是为了解决web主体型的不足,这种模式的一个最大特点是,原生开发和h5开发共存,也就是说,对于一些性能要求很高的页面模块,用原生来完成,对于一些通用型模块,用h5和js来完成.
这种模式通用有跨平台特性,而且用户体验号,性能高,不逊色与原生,但是有一个很大的限制就是,采用这种模式需要一定的技术前提 也就是说这种模式不同于web主体型可以直接用第三方框架,这种模式一般是一些有技术支持的公司自己实现的,包括H5和原生的通信,原生API提供,容器的一些处理全部由原生人员来完成,所以说,使用这种技术的前提是得有专业的原生人员(包括Android,iOS)以及业务开发人员(原生开发负责功能,前端解决简单通用h5功能) 当然了,如果技术上没有问题,用这种方案开发出来的App体验是很好的,而且性能也不逊色原生,所以是一种很优的方案
- Hybrid app 基本原理:通过JSBridge,H5页面可以调用Native的api,Native也可调用H5页面的方法或者通知H5页面回调,如图:
React Native
Facebook发起的开源的一套新的APP开发方案,使用JS+部分原生语法来实现功能。初次学习成本较高,但是在入门后,经过良好的封装也能够实现大部分的跨平台。而且体验很好。
优点:
- 虽然说开发成本大于Hybrid模式,但是小于原生模式,大部分代码可复用。
- 性能体验高于Hybrid,不逊色与原生。
- 开发人员单一技术栈,一次学习,跨平台开发。
- 社区繁荣,遇到问题容易解决。
缺点:
- 虽然可以部分跨平台,但并不是Hybrid中的一次编写,两次运行那种,而是不同平台代码有所区别。
- 开发人员学习有一定成本。无法像Hybrid模式一样平滑。
React Native 和 Weex 的原理。
- React Native原理其实跟Weex差不多,底层也会把React转换为原生API。
- React Native和Weex区别在于跨平台上面,Weex只要写一套代码,React Native需要iOS,安卓都写,说明React Native底层解析原生API是分开实现的,iOS一套,安卓一套。
- React Native会在一开始生成OC模块表,然后把这个模块表传入JS中,JS参照模块表,就能间接调用OC的代码。 相当于买了一个机器人(OC),对应一份说明书(模块表),用户(JS)参照说明书去执行机器人的操作。
了解更多 React Native 请点击这里
了解更多 Weex 请点击这里
没有说哪种方式最好,只能根据需求以及时机来选择符合当前业务的开发方式是最好的。
QQ技术交流群:214541576
微信公众号:shavekevin
开发者头条:
热爱生活,分享快乐。好记性不如烂笔头。多写,多记,多实践,多思考。