iOS面试题 - 横扫千军之战胜篇
1.谈谈 tableview 的重用机制。
-
为什么要“重用”?iPhone 重用机制是为了实现大量数据显示而采用的一种节省内存的机制。如果一个 tableview 有几百个 cell,这个内存消耗无疑是很恐怖的。再加上 cell 中还有 image 之类的资源。很容易出现 memory warning 甚至 crash !!!
-
重用代码
static NSString *CellTableIdentifier = @"cell "; UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier: CellTableIdentifier]; if (cell == nil) { cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellTableIdentifier]; }
关键函数
- (__kindof UITableViewCell *)dequeueReusableCellWithIdentifier:(NSString *)identifier forIndexPath:(NSIndexPath *)indexPath;
-
文档说明如下:
Returns a reusable table-view cell object for the specified reuse identifier and adds it to the table.
它返回的是一个受 identifier 管理定位的可重用的 tableViewCell。 -
那么它是如何重用的?
举例:假设系统启动的时候,tableView 可以显示 7 个 tableViewCell ,并且都有 tag 值,是 0 - 6。咱们把 tableView 向上滑动,那么 tag 为 0 的 Cell 将会移动到 tag 为 6 的 Cell 下面。重新设置属性。为 1 的 Cell 会移动到 0 的 Cell 下面。。。 这就是 “可重用”。
但是有的同学会问了:经常会有 cell 重叠的情况发生, 这个很容易理解,因为 Cell 滑出界面并被放入重用队列时, cell 中的内容不会消失,可以通过下面代码解决。- (void)layoutSubviews { [super layoutSubviews]; /*这里面对属性的值进行更改*/ }
2.静态库的原理是什么?你有没有自己写过静态编译库,遇到了哪些问题?
- 库本质上讲是一种可执行的二进制格式,可以载入内存中执行。是程序代码的集合,共享代码的一种方式。
- 静态库是闭源库,不公开源代码,都是编译后的二进制文件,不暴露具体实现。
- 静态库 一般都是以 .a 或者 .framework 形式存在。
- 静态库编译的文件比较大,因为整个函数库的数据都会被整合到代码中,这样的好处就是编译后的程序不需要外部的函数库支持,不好的一点就是如果改变静态函数库,就需要程序重新编译。多次使用就有多份冗余拷贝。
- 使用静态库的好处:模块化分工合作、可重用、避免少量改动导致大量的重复编译链接。
- 一般公司都会有核心开发团队和普通开发团队,然后公司的核心业务由核心开发团队写成静态库然后让普通开发团队调用,这样就算普通开发团队离职也带不走公司的核心业务代码。一般核心开发团队是不会离职的。
- 有静态库自然就有动态库了。这里所谓的静态和动态是相对编译期和运行期的。静态库在程序编译时会被链接到代码中,程序运行时将不再需要改静态库,而动态库在编译时不会被链接到代码中,只有程序运行时才会被载入,所以 hook 别人程序或者说做插件都是运用了 runtime 机制,然后动态库注入修改的。
- 制作 .a 文件时候,要注意 CPU 架构的支持,i386、X86_64、 armv7、armv7s。 查看可以通过命令 “ lipo -info 静态库名称” 。模拟器 .a 文件和真机 .a 文件合并可以通过 "lipo -create 模拟器静态库1名 真机静态库2名 -output 新静态库名称"
一些坑
-
命名不要太随意,毕竟是被别人拿过去用的要能看懂。
-
framework中用到了NSClassFromString,但是转换出来的class 一直为nil。解决方法:在主工程的【Other Linker Flags】需要添加参数【-ObjC]即可。
-
如果Xcode找不到框架的头文件,你可能是忘记将它们声明为public了。 解决方法:进入target的Build Phases页,展开Copy Headers项,把需要public的头文件从Project或Private部分拖拽到Public部分。
-
尽量不要用 xib 。由于静态框架采用静态链接,linker会剔除所有它认为无用的代码。不幸的是,linker不会检查xib文件,因此如果类是在xib中引用,而没有在O-C代码中引用,linker将从最终的可执行文件中删除类。这是linker的问题,不是框架的问题(当你编译一个静态库时也会发生这个问题)。苹果内置框架不会发生这个问题,因为他们是运行时动态加载的,存在于iOS设备固件中的动态库是不可能被删除的。
有两个解决的办法:1、 让框架的最终用户关闭linker的优化选项,通过在他们的项目的Other Linker Flags中添加-ObjC和-all_load。
2、 在框架的另一个类中加一个该类的代码引用。例如,假设你有个MyTextField类,被linker剔除了。假设你还有一个MyViewController,它在xib中使用了MyTextField,MyViewController并没有被剔除。你应该这样做:
在MyTextField中:
+(void)forceLinkerLoad_ {}
在MyViewController中:
+(void)initialize { [MyTextField forceLinkerLoad_]; }
他们仍然需要添加-ObjC到linker设置,但不需要强制all_load了。
第2种方法需要你多做一点工作,但却让最终用户避免在使用你的框架时关闭linker优化(关闭linker优化会导致object文件膨胀)。
3.谈谈你对HTTP 、TCP、 IP、socket 协议的理解。
HTTP
-
超文本传输协议(HTTP,HyperText Transfer Protocol)
HTTP 协议对应应用层,HTTP 协议是基于 TCP 连接的。HTTP 链接就是所谓的短连接,即客户端向服务器发送一次请求,服务器端响应后连接即会断掉。 - HTTP 1.0中,客户端的每次请求都要求建立一次单独的连接,在处理完本次请求后,就自动释放连接。
HTTP 1.1则可以在一次连接中处理多个请求,并且多个请求可以重叠进行,不需要等待一个请求结束后再发送下一个请求。 - 因为 HTTP 是“短连接”,所以要保持客户端程序的在线状态,需要不断的向服务器发起连接请求。一般的做法就是不需要获取任何数据,客户端也保持每隔一段固定的时间向服务器发送一次“保持连接”的请求,服务器在收到该请求后对客户端进行回复,表示知道客户端“在线”。若服务器长时间无法收到客户端的请求,则认为客户端“下线”,若客户端长时间无法收到服务器的回复,则认为网络已经断开。
TPC/IP
-
TPC/IP 协议是传输层协议,主要解决数据如何在网络中传输。“IP”代表网际协议,TCP和UDP使用该协议从一个网络传送数据包到另一个网络。把IP想像成一种高速公路,它允许其它协议在上面行驶并找到到其它电脑的出口。TCP和UDP是高速公路上的“卡车”,它们携带的货物就是像HTTP,文件传输协议FTP这样的协议等。
你应该能理解,TCP和UDP是FTP,HTTP和SMTP之类使用的传输层协议。虽然TCP和UDP都是用来传输其他协议的,它们却有一个显著的不同:TCP提供有保证的数据传输,而UDP不提供。这意味着TCP有一个特殊的机制来确保数据安全的不出错的从一个端点传到另一个端点,而UDP不提供任何这样的保证。
下面的图表试显示不同的TCP/IP和其他的协议在最初OSI模型中的位置:
TCP:IP和其他的协议在OSI模型中的位置.jpg -
TCP 标志位,有以下6种标示
1、SYN(synchronous建立联机)
2、ACK(acknowledgement 确认)
3、PSH(push传送)
4、FIN(finish结束)
5、RST(reset重置)
6、URG(urgent紧急)
Sequence number(顺序号码)
Acknowledge number(确认号码) -
客户端 TCP 状态迁移:
CLOSED->SYN_SENT->ESTABLISHED->FIN_WAIT_1->FIN_WAIT_2->TIME_WAIT->CLOSED -
服务器TCP状态迁移:
CLOSED->LISTEN->SYN收到->ESTABLISHED->CLOSE_WAIT->LAST_ACK->CLOSED -
各个状态的意义如下:
1、LISTEN - 侦听来自远方TCP端口的连接请求;
2、SYN-SENT -在发送连接请求后等待匹配的连接请求;
3、SYN-RECEIVED - 在收到和发送一个连接请求后等待对连接请求的确认;
4、ESTABLISHED- 代表一个打开的连接,数据可以传送给用户;
5、FIN-WAIT-1 - 等待远程TCP的连接中断请求,或先前的连接中断请求的确认;
6、FIN-WAIT-2 - 从远程TCP等待连接中断请求;
7、CLOSE-WAIT - 等待从本地用户发来的连接中断请求;
8、CLOSING -等待远程TCP对连接中断的确认;
9、LAST-ACK - 等待原来发向远程TCP的连接中断请求的确认;
10、TIME-WAIT -等待足够的时间以确保远程TCP接收到连接中断请求的确认;
11、CLOSED - 没有任何连接状态; -
TCP/IP 三次握手
1、第一次握手:建立连接时,客户端A发送SYN包(SYN=j)到服务器B,并进入SYN_SEND状态,等待服务器B确认。
2、第二次握手:服务器B收到SYN包,必须确认客户A的SYN(ACK=j+1),同时自己也发送一个SYN包(SYN=k),即SYN+ACK包,此时服务器B进入SYN_RECV状态。
3、第三次握手:客户端A收到服务器B的SYN+ACK包,向服务器B发送确认包ACK(ACK=k+1),此包发送完毕,客户端A和服务器B进入ESTABLISHED状态,完成三次握手。 完成后,客户端和服务器开始传送数据。
4、由于TCP连接是全双工的,因此每个方向都必须单独进行关闭。这个原则是当一方完成它的数据发送任务后就能发送一个FIN来终止这个方向的连接。收到一个 FIN只意味着这一方向上没有数据流动,一个TCP连接在收到一个FIN后仍能发送数据。首先进行关闭的一方将执行主动关闭,而另一方执行被动关闭。CP的连接的拆除需要发送四个包,因此称为四次挥手(four-way handshake)。客户端或服务器均可主动发起挥手动作,在socket编程中,任何一方执行close()操作即可产生挥手操作。
(1)客户端A发送一个FIN,用来关闭客户A到服务器B的数据传送。
(2)服务器B收到这个FIN,它发回一个ACK,确认序号为收到的序号加1。和SYN一样,一个FIN将占用一个序号。
(3)服务器B关闭与客户端A的连接,发送一个FIN给客户端A。
(4)客户端A发回ACK报文确认,并将确认序号设置为收到序号加1。
-
深入理解TCP连接的释放:
由于TCP连接是全双工的,因此每个方向都必须单独进行关闭。这原则是当一方完成它的数据发送任务后就能发送一个FIN来终止这个方向的连接。收到一个 FIN只意味着这一方向上没有数据流动,一个TCP连接在收到一个FIN后仍能发送数据。首先进行关闭的一方将执行主动关闭,而另一方执行被动关闭。
TCP协议的连接是全双工连接,一个TCP连接存在双向的读写通道。
简单说来是 “先关读,后关写”,一共需要四个阶段。以客户机发起关闭连接为例:
1.服务器读通道关闭
2.客户机写通道关闭
3.客户机读通道关闭
4.服务器写通道关闭
关闭行为是在发起方数据发送完毕之后,给对方发出一个FIN(finish)数据段。直到接收到对方发送的FIN,且对方收到了接收确认ACK之后,双方的数据通信完全结束,过程中每次接收都需要返回确认数据段ACK。
详细过程:
第一阶段 客户机发送完数据之后,向服务器发送一个FIN数据段,序列号为i;
1.服务器收到FIN(i)后,返回确认段ACK,序列号为i+1,关闭服务器读通道;
2.客户机收到ACK(i+1)后,关闭客户机写通道;
(此时,客户机仍能通过读通道读取服务器的数据,服务器仍能通过写通道写数据)
第二阶段 服务器发送完数据之后,向客户机发送一个FIN数据段,序列号为j;
3.客户机收到FIN(j)后,返回确认段ACK,序列号为j+1,关闭客户机读通道;
4.服务器收到ACK(j+1)后,关闭服务器写通道。
这是标准的TCP关闭两个阶段,服务器和客户机都可以发起关闭,完全对称。
FIN标识是通过发送最后一块数据时设置的,标准的例子中,服务器还在发送数据,所以要等到发送完的时候,设置FIN(此时可称为TCP连接处于半关闭状态,因为数据仍可从被动关闭一方向主动关闭方传送)。如果在服务器收到FIN(i)时,已经没有数据需要发送,可以在返回ACK(i+1)的时候就设置FIN(j)标识,这样就相当于可以合并第二步和第三步。 -
TCP的 TIME_WAIT 和 CLOSE_WAIT 状态
CLOSE_WAIT:
发起TCP连接关闭的一方称为client,被动关闭的一方称为server。被动关闭端未发出FIN的TCP状态是CLOASE_WAIT。出现这种状况一般都是由于server端代码的问题,如果你的服务器上出现大量CLOSE_WAIT,应该要考虑检查代码。
TIME_WAIT:
根据TCP协议定义的3次握手断开连接规定,发起socket主动关闭的一方 socket将进入TIME_WAIT状态。TIME_WAIT状态将持续2个MSL(Max Segment Lifetime),在Windows下默认为4分钟,即240秒。TIME_WAIT状态下的socket不能被回收使用. 具体现象是对于一个处理大量短连接的服务器,如果是由服务器主动关闭客户端的连接,将导致服务器端存在大量的处于TIME_WAIT状态的socket, 甚至比处于Established状态下的socket多的多,严重影响服务器的处理能力,甚至耗尽可用的socket,停止服务。
socket
-
socket连接就是所谓的长连接,理论上客户端和服务器端一旦建立起连接将不会主动断掉;但是由于各种环境因素可能会是连接断开,比如说:服务器端或客户端主机down了,网络故障,或者两者之间长时间没有数据传输,网络防火墙可能会断开该连接以释放网络资源。所以当一个socket连接中没有数据的传输,那么为了维持连接需要发送心跳消息~~具体心跳消息格式是开发者自己定义的。
-
套接字(socket)是通信的基石,是支持TCP/IP协议的网络通信的基本操作单元。它是网络通信过程中端点的抽象表示,包含进行网络通信必须的五种信息:连接使用的协议,本地主机的IP地址,本地进程的协议端口,远地主机的IP地址,远地进程的协议端口。
-
我们平时说的最多的socket是什么呢,实际上socket是对TCP/IP协议的封装,Socket本身并不是协议,而是一个调用接口(API),通过Socket,我们才能使用TCP/IP协议。 实际上,Socket跟TCP/IP协议没有必然的联系。Socket编程接口在设计的时候,就希望也能适应其他的网络协议。所以说,Socket的出现 只是使得程序员更方便地使用TCP/IP协议栈而已,是对TCP/IP协议的抽象,从而形成了我们知道的一些最基本的函数接口,比如create、 listen、connect、accept、send、read和write等等。网络有一段关于socket和TCP/IP协议关系的说法比较容易理解:
“TCP/IP只是一个协议栈,就像操作系统的运行机制一样,必须要具体实现,同时还要提供对外的操作接口。这个就像操作系统会提供标准的编程接口,比如win32编程接口一样,TCP/IP也要提供可供程序员做网络开发所用的接口,这就是Socket编程接口。”
实际上,传输层的TCP是基于网络层的IP协议的,而应用层的HTTP协议又是基于传输层的TCP协议的,而Socket本身不算是协议,就像上面所说,它只是提供了一个针对TCP或者UDP编程的接口。socket是对端口通信开发的工具,它要更底层一些. -
Socket是一个针对TCP和UDP编程的接口,你可以借助它建立TCP连接等等。而TCP和UDP协议属于传输层 。
而http是个应用层的协议,它实际上也建立在TCP协议之上(HTTP是轿车,提供了封装或者显示数据的具体形式;Socket是发动机,提供了网络通信的能力)。Socket是对TCP/IP协议的封装,Socket本身并不是协议,而是一个调用接口(API),通过Socket,我们才能使用TCP/IP协议。Socket的出现只是使得程序员更方便地使用TCP/IP协议栈而已,是对TCP/IP协议的抽象,从而形成了我们知道的一些最基本的函数接口。
-
短连接:
连接->传输数据->关闭连接
HTTP是无状态的,浏览器和服务器每进行一次HTTP操作,就建立一次连接,但任务结束就中断连接。
也可以这样说:短连接是指SOCKET连接后发送后接收完数据后马上断开连接。 -
长连接:
连接->传输数据->保持连接 -> 传输数据-> 。。。 ->关闭连接。
长连接指建立SOCKET连接后不管是否使用都保持连接,但安全性较差。 -
http 的长连接:
HTTP也可以建立长连接的,使用Connection:keep-alive,HTTP 1.1默认进行持久连接。HTTP1.1和HTTP1.0相比较而言,最大的区别就是增加了持久连接支持(貌似最新的 http1.0 可以显示的指定 keep-alive),但还是无状态的,或者说是不可以信任的。 -
长连接和短连接的使用环境:
长连接多用于操作频繁,点对点的通讯,而且连接数不能太多情况,。每个TCP连接都需要三步握手,这需要时间,如果每个操作都是先连接,再操作的话那么处理速度会降低很多,所以每个操作完后都不断开,次处理时直接发送数据包就OK了,不用建立TCP连接。例如:数据库的连接用长连接, 如果用短连接频繁的通信会造成socket错误,而且频繁的socket 创建也是对资源的浪费。
而像WEB网站的http服务一般都用短链接,因为长连接对于服务端来说会耗费一定的资源,而像WEB网站这么频繁的成千上万甚至上亿客户端的连接用短连接会更省一些资源,如果用长连接,而且同时有成千上万的用户,如果每个用户都占用一个连接的话,那可想而知吧。所以并发量大,但每个用户无需频繁操作情况下需用短连好。
总之,长连接和短连接的选择要视情况而定。 -
发送接收方式:
1、异步
报文发送和接收是分开的,相互独立的,互不影响。这种方式又分两种情况:
(1)异步双工:接收和发送在同一个程序中,由两个不同的子进程分别负责发送和接收
(2)异步单工:接收和发送是用两个不同的程序来完成。
2、同步
报文发送和接收是同步进行,既报文发送后等待接收返回报文。 同步方式一般需要考虑超时问题,即报文发出去后不能无限等待,需要设定超时时间,超过该时间发送方不再等待读返回报文,直接通知超时返回。
在长连接中一般是没有条件能够判断读写什么时候结束,所以必须要加长度报文头。读函数先是读取报文头的长度,再根据这个长度去读相应长度的报文。
4.谈谈你对iOS中沙盒机制的理解。
-
iOS 的沙盒机制(sandbox)
每个iOS应用都有自己的应用沙盒,应用沙盒就是文件系统目录。
1.每个应用程序的活动范围都限定在自己的沙盒里
2.不能随意跨越自己的沙盒去访问别的应用程序沙盒中的内容
(iOS8已经部分开放访问extension)
3.在访问别人沙盒内的数据时需要访问权限。 -
沙盒的组成:
1、Documents:
Documents中一般保存应用程序本身产生文件数据,例如游戏进度,绘图软件的绘图等, iTunes备份和恢复的时候,会包括此目录。
注意:在此目录下不要保存从网络上下载的文件,否则app无法上架!(曾试过 plist 存小文件扔进去 上架通过)
2、Library:
(1)、Caches:
此目录用来保存应用程序运行时生成的需要持久化的数据,这些数据一般存储体积比较大,又不是十分重要,比如网络请求数据等。这些数据需要用户负责删除。iTunes同步设备时不会备份该目录。(2)、Preferences:
此目录保存应用程序的所有偏好设置,iOS的Settings(设置)应用会在该目录中查找应用的设置信息。iTunes同步设备时会备份该目录
在Preferences/下不能直接创建偏好设置文件,而是应该使用NSUserDefaults类来取得和设置应用程序的偏好.3、tmp:
此目录保存应用程序运行时所需的临时数据,使用完毕后再将相应的文件从该目录删除。应用没有运行时,系统也可能会清除该目录下的文件。iTunes同步设备时不会备份该目录 -
手机越狱后跟沙盒的关系
不同的越狱方案对沙盒会有所不同的影响,iOS 越狱不代表沙盒(sandbox)的移除,但通常都会使其变得更“虛弱”。越狱之后,原本的一些私密文件,比如短信资料(/var/mobile/Library/SMS/sms.db),AppStore安装的App仍旧没有访问权限。但是,越狱后App能获得应用文件夹(/var/mobile/Aplications/)的读写权限,就是说,我能够遍历找到你的支付宝、招行、QQ、微信的App里面的用户资料,这仍旧会导致很大的安全问题。即使在AppStore上线的App,也能轻易根据当前是否越狱来作出不同的动作,Apple审核检查不到这一点。
-
越狱本身的方法就是透过iOS现有的漏洞进行越狱,代表越狱是有风险性的情况发生,不过不可就认为越狱不安全,在越狱后iOS沙盒并没有被破坏,使用者虽然获取了root权限,并不表示就可让App都能够拥有root权限,可自动将指令写入至系统资料夹中,不过越狱后,在iOS上发现的漏洞或BUG,越狱界都会有开发者在第一时间内发布修补漏洞,先前就有不少案例。
在越狱后我们能够享有各种不同的插件,可让iOS设备实现不同功能,这些插件我们都会透过Cydia一些公认安全的插件源(如Bigboss、ModMyi)进行下载安装,这些软体源就像是AppStore会有审核机制、会员注册与付费购买机制,在上面所安装的插件都有一定的高信任与安全,其中比较好用的插件也都必须付费才能够使用,毕竟这些都是由不同开发者所开发出来的产品,如开发者没有收入来源,为何还要继续维护与更新下去呢?有些插件会由作者自己架设插件源免费提供分享的也有,不过也延伸出了有些越狱用户贪图免费,透过底下几种方式来安装,导致造成插件功能不正常、Cydia不稳定或是造成出错问题发生。
5.请你谈谈你对视频播放器/直播的理解。如果封装一个视频播放器你会怎么做?封装中遇到哪些问题?你是怎么解决的?
视频播放器/直播的理解:
-
流媒体协议:
常用的流媒体协议有以下几种:-
实时传输协议 RTP 与 RTCP
RTP(Real-time Transport Protocol) 是用于 Internet 上针对多媒体数据流的一种传输协议。RTP 由两个紧密连接部分组成:- RTP:传送具有实时属性的数据。
- RTP 控制协议(RTCP):监控服务质量并传送正在进行的会话参与者的相关信息。
RTP 协议是建立在 UDP 协议上的。RTP 本身并没有提供按时发送机制或其它服务质量(QoS)保证,它依赖于低层服务去实现这一过程。 RTP 并不保证传送或防止无序传送,也不确定底层网络的可靠性。 RTP 实行有序传送, RTP 中的序列号允许接收方重组发送方的包序列,同时序列号也能用于决定适当的包位置,例如:在视频解码中,就不需要顺序解码。
实时传输控制协议(Real-time Transport Control Protocol,RTCP)是实时传输协议(RTP)的一个姐妹协议。RTCP为RTP媒体流提供信道外控制。RTCP定期在流多媒体会话参加者之间传输控制数据。RTCP的主要功能是为RTP所提供的服务质量提供反馈。RTCP收集相关媒体连接的统计信息,例如:传输字节数,传输分组数,丢失分组数,时延抖动,单向和双向网络延迟等等。网络应用程序可以利用RTCP所提供的信息试图提高服务质量,比如限制信息流量或改用压缩比较小的编解码器。RTCP本身不提供数据加密或身份认证,其伴生协议SRTCP(安全实时传输控制协议)则可用于此类用途。
-
实时流协议RTSP
RTSP(Real Time Streaming Protocol)是由Real Networks和Netscape共同提出的。该协议定义了一对多应用程序如何有效地通过IP网络传送多媒体数据。RTSP提供了一个可扩展框架,使实时数据,如音频与视频的受控、点播成为可能。数据源包括现场数据与存储在剪辑中的数据。该协议目的在于控制多个数据发送连接,为选择发送通道,如UDP、多播UDP与TCP提供途径,并为选择基于RTP上发送机制提供方法。RTSP(Real Time Streaming Protocol)是用来控制声音或影像的多媒体串流协议,并允许同时多个串流需求控制,传输时所用的网络通讯协定并不在其定义的范围内,服务器端可以自行选择使用TCP或UDP来传送串流内容,它的语法和运作跟HTTP 1.1类似,但并不特别强调时间同步,所以比较能容忍网络延迟。而前面提到的允许同时多个串流需求控制(Multicast),除了可以降低服务器端的网络用量,更进而支持多方视讯会议(Video Conference)。 因为与HTTP1.1的运作方式相似,所以代理服务器《Proxy》的快取功能《Cache》也同样适用于RTSP,并因RTSP具有重新导向功能,可视实际负载情况来转换提供服务的服务器,以避免过大的负载集中于同一服务器而造成延迟。
RTSP 和RTP的关系 :
RTP不象http和ftp可完整的下载整个影视文件,它是以固定的数据率在网络上发送数据,客户端也是按照这种速度观看影视文件,当影视画面播放过后,就不可以再重复播放,除非重新向服务器端要求数据。
RTSP与RTP最大的区别在于:RTSP是一种双向实时数据传输协议,它允许客户端向服务器端发送请求,如回放、快进、倒退等操作。当然,RTSP可基于RTP来传送数据,还可以选择TCP、UDP、组播UDP等通道来发送数据,具有很好的扩展性。它时一种类似与http协议的网络应用层协议。
-
实时消息传输协议RTMP/RTMPS
-
RTMP(Real Time Messaging Protocol)实时消息传送协议是Adobe Systems公司为Flash播放器和服务器之间音频、视频和数据传输 开发的开放协议。
它有三种变种:
(1)工作在TCP之上的明文协议,使用端口1935。
(2)TMPT封装在HTTP请求之中,可穿越防火墙。
(3)RTMPS类似RTMPT,但使用的是HTTPS连接。RTMP协议(Real Time Messaging Protocol)是被Flash用于对象,视频,音频的传输.这个协议建立在TCP协议或者轮询HTTP协议之上.。
RTMP协议就像一个用来装数据包的容器,这些数据既可以是AMF格式的数据,也可以是FLV中的视/音频数据.一个单一的连接可以通过不同的通道传输多路网络流.这些通道中的包都是按照固定大小的包传输的。RTMP视频播放的特点:
(1)RTMP协议是采用实时的流式传输,所以不会缓存文件到客户端,这种特性说明用户想下载RTMP协议下的视频是比较难的;
(2)视频流可以随便拖动,既可以从任意时间点向服务器发送请求进行播放,并不需要视频有关键帧。相比而言,HTTP协议下视频需要有关键帧才可以随意拖动。
(3)RTMP协议支持点播/回放(通俗点将就是支持把flv,f4v,mp4文件放在RTMP服务器,客户端可以直接播放),直播(边录制视频边播放)。
RTMP环境的架设:
因为该协议是adobe公司开发的,所以最初服务器端架设的环境是FMS(Flash Media Server),该软件为收费软件,价格昂贵。后来,开源软件red5的推出,使rtmp协议的架设成本大大缩小,但是在性能方面不如fms的稳定。此外,wowza虽然是收费的,但价格比较适中。
-
-
微软媒体服务器协议MMS
MMS(Microsoft Media Server Protocol)是用来访问并流式接收Window Media服务器中.asf文件的一种协议。MMS协议用于访问Windows Media发布点上的单播内容。MMS是连接Windows Media单播服务的默认方法。若观众在Windows Media Player中键入一个URL以连接内容,而不是通过超级链接访问内容,则他们必须是MMS协议引用该流。MMS的预设端口是1755。
-
HLS
HTTP Live Streaming(HLS)是苹果公司(Apple Inc.)实现的基于HTTP的流媒体传输协议,可实现流媒体的直播和点播,主要应用在iOS系统,为iOS设备(如iPhone、iPad)提供音视频直播和点播方案。HLS点播,基本上就是常见的分段HTTP点播,不同在于,它的分段非常小。
相对于常见的流媒体直播协议,例如RTMP协议、RTSP协议、MMS协议等,HLS直播最大的不同在于,直播客户端获取到的,并不是一个完整的数据流。HLS协议在服务器端将直播数据流存储为连续的、很短时长的媒体文件(MPEG-TS格式),而客户端则不断的下载并播放这些小文件,因为服务器端总是会将最新的直播数据生成新的小文件,这样客户端只要不停的按顺序播放从服务器获取到的文件,就实现了直播。由此可见,基本上可以认为,HLS是以点播的技术方式来实现直播。由于数据通过HTTP协议传输,所以完全不用考虑防火墙或者代理的问题,而且分段文件的时长很短,客户端可以很快的选择和切换码率,以适应不同带宽条件下的播放。不过HLS的这种技术特点,决定了它的延迟一般总是会高于普通的流媒体直播协议。
-
-
编解码
编解码器(codec)指的是一个能够对一个信号或者一个数据流进行变换的设备或者程序。这里指的变换既包括将 信号或者数据流进行编码(通常是为了传输、存储或者加密)或者提取得到一个编码流的操作,也包括为了观察或者处理从这个编码流中恢复适合观察或操作的形式的操作。编解码器经常用在视频会议和流媒体等应用中。
-
H.264
是由ITU-T视频编码专家组(VCEG)和ISO/IEC动态图像专家组MPEG)联合组成的联合视频组(JVT,Joint Video Team)提出的高度压缩数字视频编解码器标准。这个标准通常被称之为H.264/AVC(或者AVC/H.264或者H.264/MPEG-4 AVC或MPEG-4/H.264 AVC)而明确的说明它两方面的开发者。 -
优势:
1.低码率(Low Bit Rate):和MPEG2和MPEG4 ASP等压缩技术相比,在同等图像质量下,采用H.264技术压缩后的数据量只有MPEG2的1/8,MPEG4的1/3。
2.高质量的图像:H.264能提供连续、流畅的高质量图像(DVD质量)。
3.容错能力强:H.264提供了解决在不稳定网络环境下容易发生的丢包等错误的必要工具。
4.网络适应性强:H.264提供了网络抽象层(Network Abstraction Layer),使得H.264的文件能容易地在不同网络上传输(例如互联网,CDMA,GPRS,WCDMA,CDMA2000等)。 -
特点:
1.更高的编码效率:同H.263等标准的特率效率相比,能够平均节省大于50%的码率。
2.高质量的视频画面:H.264能够在低码率情况下提供高质量的视频图像,在较低带宽上提供高质量的图像传输是H.264的应用亮点。
3.提高网络适应能力:H.264可以工作在实时通信应用(如视频会议)低延时模式下,也可以工作在没有延时的视频存储或视频流服务器中。
4.采用混合编码结构:同H.263相同,H.264也使用采用DCT变换编码加DPCM的差分编码的混合编码结构,还增加了如多模式运动估计、帧内预测、多帧预测、基于内容的变长编码、4x4二维整数变换等新的编码方式,提高了编码效率。
5.H.264的编码选项较少:在H.263中编码时往往需要设置相当多选项,增加了编码的难度,而H.264做到了力求简洁的“回归基本”,降低了编码时复杂度。
6.H.264可以应用在不同场合:H.264可以根据不同的环境使用不同的传输和播放速率,并且提供了丰富的错误处理工具,可以很好的控制或消除丢包和误码。
7.错误恢复功能:H.264提供了解决网络传输包丢失的问题的工具,适用于在高误码率传输的无线网络中传输视频数据。
8.较高的复杂度:264性能的改进是以增加复杂性为代价而获得的。据估计,H.264编码的计算复杂度大约相当于H.263的3倍,解码复杂度大约相当于H.263的2倍。
-
-
FFmpeg
是一套可以用来记录、转换数字音频、视频,并能将其转化为流的开源计算机程序。采用LGPL或GPL许可证。它提供了录制、转换以及流化音视频的完整解决方案。它包含了非常先进的音频/视频编解码库libavcodec,为了保证高可移植性和编解码质量,libavcodec里很多code都是从头开发的。- 功能
多媒体视频处理工具FFmpeg有非常强大的功能包括视频采集功能、视频格式转换、视频抓图、给视频加水印等。ffmpeg视频采集功能非常强大,不仅可以采集视频采集卡或USB摄像头的图像,还可以进行屏幕录制,同时还支持以 RTP 方式将视频流传送给支持 RTSP 的流媒体服务器,支持直播应用。
- 功能
-
AAC
全称Advanced Audio Coding,是一种专为声音数据设计的文件压缩格式。与MP3不同,它采用了全新的算法进行编码,更加高效,具有更高的“性价比”。利用AAC格式,可使人感觉声音质量没有明显降低的前提下,更加小巧。苹果ipod、诺基亚手机支持AAC格式的音频文件。相对于mp3,AAC格式的音质更佳,文件更小。- 优点
1、提升的压缩率:可以以更小的文件大小获得更高的音质。
2、支持多声道:可提供最多48个全音域声道。
3、更高的解析度:最高支持96KHz的采样频率。
4、提升的解码效率:解码播放所占的资源更少 - 不足
AAC属于有损压缩的格式,与时下流行的APE、FLAC等无损格式相比音质存在“本质上”的差距。加之,传输速度更快的USB3.0和16G以上大容量MP3正在加速普及,也使得AAC头上“小巧”的光环不复存在。
- 优点
-
HLS分段生成策略及m3u8索引文件
m3u8,是HTTP Live Streaming直播的索引文件。m3u8基本上可以认为就是.m3u格式文件,区别在于,m3u8文件使用UTF-8字符编码。#EXTM3U m3u文件头,必须放在第一行 #EXT-X-MEDIA-SEQUENCE 第一个TS分片的序列号 #EXT-X-TARGETDURATION 每个分片TS的最大的时长 #EXT-X-ALLOW-CACHE 是否允许cache #EXT-X-ENDLIST m3u8文件结束符 #EXTINF extra info,分片TS的信息,如时长,带宽等
- HLS的分段策略,基本上推荐是10秒一个分片,当然,具体时间还要根据分好后的分片的实际时长做标注。通常来说,为了缓存等方面的原因,在索引文件中会保留最新的三个分片地址,以类似“滑动窗口”的形式,进行更新。
直播现在大部分都是引用第三方服务的。简单封装播放器如下
#import < UIKit/UIKit.h >
#import < MediaPlayer/MediaPlayer.h >
#import < AVKit/AVKit.h >
@interface ZrMoviePlayer : UIView
@property (nonatomic,strong) MPMoviePlayerController *moviePlayer;//视频播放控制器
/**
* 播放资源地址
*/
@property (nonatomic,strong) NSString *videoUrl;
/**
* 播放资源缩略图
*/
@property (nonatomic,strong) UIImageView *caver;
/**
* 初始化
*
* @param frame frame
* @param url videoUrl
*
* @return self
*/
-(instancetype)initWithFrame:(CGRect)frame videoUrl:(NSString *)url;
/**
* 播放资源缩略图
*
* @param url picUrl
*/
- (void)showCoverWithUrl:(NSString *)url;
@end
.m
#import "ZrMoviePlayer.h"
@interface ZrMoviePlayer ()
@end
@implementation ZrMoviePlayer
-(instancetype)initWithFrame:(CGRect)frame videoUrl:(NSString *)url{
self.videoUrl = url;
self = [super initWithFrame:frame];
if (self) {
/** [用户手动点击播放 默认暂停]*/
//[self.moviePlayer play];
[selfaddNotification];
/** 获取缩略图 */
//[self thumbnaiImageRequest];
[self addGest];
}
return self;
}
/**
* 添加手势
*/
-(void)addGest {
UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(moviePicCoverTapGesture)];
[self addGestureRecognizer:tapGesture];
}
/**
* 移除缩略图 播放视频
*/
-(void)moviePicCoverTapGesture{
[self.caver removeFromSuperview];
[self.moviePlayer play];
}
- (void)dealloc{
/** 移除所有通知监控 */
[[NSNotificationCenter defaultCenter]removeObserver:self];
}
#pragma mark -- 私有方法
/**
* 获得本地文件路径
*
* @return 文件路径
*/
- (NSURL *)getFileUrl{
NSString *urlStr = [[NSBundle mainBundle]pathForResource:@"" ofType:nil];
return [NSURL URLWithString:urlStr];
}
/**
* 取得网络文件路径
*
* @return 文件路径
*/
- (NSURL *)getNetworkUrl{
NSString *urlStr = _videoUrl;
urlStr = [urlStr stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
return [NSURL URLWithString:urlStr];
}
/**
* 创建媒体播放器
*
* @return moviePlayer
*/
- (MPMoviePlayerController *)moviePlayer{
if (!_moviePlayer) {
NSURL *url = [self getNetworkUrl];
_moviePlayer = [[MPMoviePlayerController alloc]initWithContentURL:url];
_moviePlayer.view.frame = self.bounds;
_moviePlayer.view.autoresizingMask = UIViewAutoresizingFlexibleWidth|UIViewAutoresizingFlexibleHeight;
[self addSubview:_moviePlayer.view];
}
return _moviePlayer;
}
/**
* 获取视频缩略图
*/
- (void)thumbnaiImageRequest{
/** 获取13.0s、21.5s的缩略图 */
[self.moviePlayer requestThumbnailImagesAtTimes:@[@13.0,@21.5] timeOption:MPMovieTimeOptionNearestKeyFrame];
}
#pragma mark - 控制器通知
/**
* 添加通知监控多媒体控制器状态
*/
- (void)addNotification{
NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter];
[notificationCenter addObserver:self
selector:@selector(mediaPlayerPlaybackFinished:)
name:MPMoviePlayerPlaybackDidFinishNotification
object:self.moviePlayer];
[notificationCenter addObserver:self
selector:@selector(mediaPlayerPlaybackStateChange:)
name:MPMoviePlayerPlaybackStateDidChangeNotification
object:self.moviePlayer];
[notificationCenter addObserver:self
selector:@selector(mediaPlayerThumbnailRequestFinished:)
name:MPMoviePlayerThumbnailImageRequestDidFinishNotification
object:self.moviePlayer];
}
/**
* 播放状态改变,注意播放完成时的状态是暂停
*
* @param notify 通知对象
*/
- (void)mediaPlayerPlaybackStateChange:(NSNotification *)notify{
switch (self.moviePlayer.playbackState) {
case MPMoviePlaybackStatePlaying:
NSLog(@"正在播放");
// [[NSNotificationCenter defaultCenter] postNotificationName:MoviePlayNotification object:nil];
break;
case MPMoviePlaybackStatePaused:
NSLog(@"暂停播放");
// [[NSNotificationCenter defaultCenter] postNotificationName:MoviePauseOrStopNotification object:nil];
break;
case MPMoviePlaybackStateStopped:
NSLog(@"停止播放");
// [[NSNotificationCenter defaultCenter] postNotificationName:MoviePauseOrStopNotification object:nil];
break;
default:
NSLog(@"播放状态:%ld",(long)self.moviePlayer.playbackState);
break;
}
}
- (void)mediaPlayerPlaybackFinished:(NSNotification *)notify{
NSLog(@"播放完成");
}
/**
* 缩略图请求完成,此方法每次截图成功后都会调用一次
*
* @param notify 通知对象
*/
- (void)mediaPlayerThumbnailRequestFinished:(NSNotification *)notify{
NSLog(@"视频截图成功");
UIImage *image = notify.userInfo[MPMoviePlayerThumbnailImageKey];
// 保存图片到相册(首次调用会请求用户获访问相册权限)
UIImageWriteToSavedPhotosAlbum(image, nil, nil, nil);
}
/**
* 播放资源缩略图
*
* @param url picUrl
*/
- (void)showCoverWithUrl:(NSString *)url
{
UIImageView *caver = [[UIImageView alloc] init];
_caver = caver;
[caver sd_setImageWithURL:[NSURL URLWithString:url]placeholderImage:[UIImage imageNamed:@"videoPlaceHolder"]];
[self addSubview:caver];
UIImageView *pause = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 100, 100)];
pause.image = [UIImage imageNamed:@"zr_pause"];
[caver addSubview:pause];
caver.sd_layout
.leftSpaceToView(self,0)
.topSpaceToView(self,0)
.rightSpaceToView(self,0)
.bottomSpaceToView(self,0);
pause.center = CGPointMake(self.center.x, self.center.y-20);
}
@end
这篇文章讲解了 得到 和 喜马拉雅FM 的播放器的实现。
喜马拉雅FM的头文件点击下载 密码: u4uu
6.谈谈你对JSON XML的理解。
-
JSON是什么?
- JSON 指的是 JavaScript 对象表示法(JavaScript Object Notation)。
- JSON 是轻量级的文本数据交换格式。
- JSON 独立于语言(JSON 使用 JavaScript 语法来描述数据对象,但是 JSON 仍然独立于语言和平台。JSON 解析器和 JSON 库支持许多不同的编程语言。)
- JSON 具有自我描述性,更易理解。
-
JSON的规则很简单: 对象是一个无序的 “ ‘名称/值’ 对” 集合。一个对象以“{”(左括号)开始,“}”(右括号)结束。每个“名称”后跟一个“:”(冒号);“‘名称/值’ 对”之间使用“,”(逗号)分隔。
-
什么是 XML?
1、XML 指可扩展标记语言(EXtensible Markup Language)。
2、XML 是一种标记语言,很类似 HTML。
3、XML 的设计宗旨是传输数据,而非显示数据。
4、XML 标签没有被预定义。您需要自行定义标签。
5、XML 被设计为具有自我描述性。 -
JSON 与 XML 的互相比较
- 简单的数据
XML
JSON<person> <name>xiaoMing</name> <age>20</age> </person>
{ "name":"xiaoMing", "age":20 }
- 复杂的数据
XML
JSON<section> <title>BOOK</title> <signing> <author name="author-1"/> <book title="book1" price="$11"/> </signing> <signing> <author name="author-2"/> <book title="book2" price="$22"/> </signing> </section>
"section":{ "title":"BOOK", "signing":[ { "author": { "name":"author-1" }, "book": { "title":"book1", "price":"$11" } }, { "author": { "name":"author-2" }, "book": { "title":"book2", "price":"$22" } }] }
- 简单的数据
-
JSON和XML的优缺点
XML- 优点
(1)格式统一,符合标准;
(2)容易与其他系统进行远程交互,数据传输比较方便。 - 缺点
(1)XML文件庞大,文件格式复杂,传输占带宽;
(2)服务器端和客户端都需要花费大量代码来解析XML,导致服务器端和客户端代码变得异常复杂且不易维护;
(3)客户端不同浏览器之间解析XML的方式不一致,需要重复编写很多代码;
(4)服务器端和客户端解析XML花费较多的资源和时间。
JSON
-
优点
(1)数据格式比较简单,易于读写,格式都是压缩的,占用带宽小;
(2)易于解析,客户端JavaScript可以简单的通过eval_r()进行JSON数据的读取;
(3)支持多种语言,包括ActionScript, C, C#, ColdFusion, Java, JavaScript, Perl, PHP, Python, Ruby等服务器端语言,便于服务器端的解析;
(4)在PHP世界,已经有PHP-JSON和JSON-PHP出现了,偏于PHP序列化后的程序直接调用,PHP服务器端的对象、数组等能直接生成JSON格式,便于客户端的访问提取;
(5)因为JSON格式能直接为服务器端代码使用,大大简化了服务器端和客户端的代码开发量,且完成任务不变,并且易于维护。 -
缺点
(1)没有XML格式这么推广的深入人心和喜用广泛,没有XML那么通用性;
(2)JSON格式目前在Web Service中推广还属于初级阶段。
- 优点
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) 。
算法步骤:
创建一个堆H[0..n-1]
把堆首(最大值)和堆尾互换
- 把堆的尺寸缩小1,并调用shift_down(0),目的是把新的数组顶端数据调整到相应位置
-
重复步骤2,直到堆的尺寸为1
堆排序算法.gif
归并排序
归并排序(Merge sort,台湾译作:合并排序)是建立在归并操作上的一种有效的排序算法。该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。
算法步骤:
- 申请空间,使其大小为两个已经排序序列之和,该空间用来存放合并后的序列
- 设定两个指针,最初位置分别为两个已经排序序列的起始位置
- 比较两个指针所指向的元素,选择相对小的元素放入到合并空间,并移动指针到下一位置
- 重复步骤3直到某一指针达到序列尾
-
将另一序列剩下的所有元素直接复制到合并序列尾
归并算法.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。
- 优点:
1、用户体验最佳,优质的用户界面,华丽的交互。
2、不同平台提供不同体验。
3、节省带宽成本。
4、可访问本地资源,打开速度快。 - 缺点:
1、维护多个版本的成本比较高。
2、开发成本比较大。
3、盈利需要与第三方分成。
4、AppStore 审核机制比较麻烦。
Web App(网页应用)
- 指使用Html开发的移动端网页App,类似微信小程序,整个App都是网页。
- 优点:
1、用户不需要安装,不会占用手机内存。
2、开发成本低,维护更新简单。
3、跨平台好。 - 缺点:
1、用户体验不好,不能离线,必须联网。
2、现在纯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+部分原生语法来实现功能。初次学习成本较高,但是在入门后,经过良好的封装也能够实现大部分的跨平台。而且体验很好。
- 优点:
1、虽然说开发成本大于Hybrid模式,但是小于原生模式,大部分代码可复用。
2、性能体验高于Hybrid,不逊色与原生。
3、开发人员单一技术栈,一次学习,跨平台开发。
4、社区繁荣,遇到问题容易解决。 - 缺点:
1、虽然可以部分跨平台,但并不是Hybrid中的一次编写,两次运行那种,而是不同平台代码有所区别。
2、开发人员学习有一定成本。无法像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)参照说明书去执行机器人的操作。