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)中,它至少会把一个元素摆到它最后的位置去。 快速排序.gif        

堆排序算法

堆排序(Heapsort)是指利用堆这种数据结构所设计的一种排序算法。堆积是一个近似完全二叉树的结构,并同时满足堆积的性质:即子结点的键值或索引总是小于(或者大于)它的父节点。 堆排序的平均时间复杂度为Ο(nlogn) 。          算法步骤: 1.创建一个堆H[0..n-1]
2.把堆首(最大值)和堆尾互换
3. 把堆的尺寸缩小1,并调用shift_down(0),目的是把新的数组顶端数据调整到相应位置
4. 重复步骤2,直到堆的尺寸为1
堆排序算法.gif        

归并排序

归并排序(Merge sort,台湾译作:合并排序)是建立在归并操作上的一种有效的排序算法。该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。         算法步骤: 1. 申请空间,使其大小为两个已经排序序列之和,该空间用来存放合并后的序列
2. 设定两个指针,最初位置分别为两个已经排序序列的起始位置
3. 比较两个指针所指向的元素,选择相对小的元素放入到合并空间,并移动指针到下一位置
4. 重复步骤3直到某一指针达到序列尾
5. 将另一序列剩下的所有元素直接复制到合并序列尾
归并算法.gif        

二分查找算法

二分查找算法是一种在有序数组中查找某一特定元素的搜索算法。搜素过程从数组的中间元素开始,如果中间元素正好是要查找的元素,则搜素过程结束;如果某一特定元素大于或者小于中间元素,则在数组大于或小于中间元素的那一半中查找,而且跟开始一样从中间元素开始比较。如果在某一步骤数组为空,则代表找不到。这种搜索算法每一次比较都使搜索范围缩小一半。折半搜索每次把搜索区域减少一半,时间复杂度为Ο(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页面回调,如图: Hybrid基本原理图.jpg        

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

开发者头条:

热爱生活,分享快乐。好记性不如烂笔头。多写,多记,多实践,多思考。    

comments powered by Disqus