项目中技术点
1.推流主要使用RTMP(RTP),视频编码H264,音频MP3.不支持浏览器 (RTC)
2.拉流,服务端下发格式FLV
一.算法:
1.不用临时变量怎么实现 swap(a, b)
a = a + b;
b = a;
a = a - b;
2.二维有序数组查找数字(二分查找)
1.比如查找值为A
2.(上来先排个序)数组从小到大排序
1.取出数组中间元素
2.把中间元素跟A进行比较。中间元素>A,那么A就位于第一元素和中间元素之前,反之同理
3.反复比较来缩小范围
4.简述排序算法
1.冒泡排序 平均时间复杂度 O(n2) 稳定
1.比较相邻的元素,如果第一个元素比第二个大,就交换
2.从第一对直至到最后一对,重复第一步操作,除了最后一个
*最快:数据正序。最慢:数据反序
2.快速排序 (本质就是 在冒泡排序基础上的递归分治法) 平均时间复杂度O(n log n) 不稳定
1.从数列中挑出基准元素
2.重新排序数列,所有元素比基准元素小就放在基准前面,大的就放后面
3.递归的把 小于基准元素的子数列 和 大于基准元素的子数列 排序
3.选择排序平均时间复杂度 O(n2) 不稳定
1.先在未排序 序列中 找到最小(大)元素,存放到排序序列的起始位置
2.再从剩余未排序元素中寻找最小(大)元素,然后放到已排序序列的末尾
3.重复第二步,直到排序完毕
4.插入排序 平均时间复杂度O(n2) 稳定
1.将第一待排序序列第一个元素看作一个有序序列,把第二个元素到最后一个元素看作未排序序列
2.从头到尾依次扫描未排序序列,将扫描到的每个元素插入到有序序列的适当位置(如果相等,将放到相等元素的后面)
二.准备问题:
1.对OC中 load 和 initialize 的异同
执行时机:load 自身没有定义,不会调用其父类方法,而initialize 会调用其父类方法
区别:load只要类所在文件被引用,就会执行,不引用则不执行。initialize只用调用才知执行,引用文件无效
共同点:方法只执行一次
2.对block的理解
1.是封装函数及其上下文的OC对象,内部有个isa指针
2.使用时注意 循环引用 __weak(不会产生强引用,自动指针为nil) __block(必须把对象置为nil,并且要调用该block)
3.怎么造成循环引用:block为了内部对象不被释放,会对对象进行强引用,而block中对象又持有该block,就造成了循环引用
block外部:__weak typeof(self) weakself = self;
block内部:__strong typeof(weakself) strongSelf = weakself;
3.对Runtime的理解 (SEL IMP 的区别)
1.runtime是将数据类型的确定由编译时推迟到运行时
2.写OC时需要runtime来创建类和对象,来进行消息发送和转发<消息机制>,最终转成C语言
3.访问私有变量
4.交换系统方法
5.动态添加属性。方法
6.为分类添加属性
7.字典转模型
*一个类(Class)持有一个分发表,在运行期分发消息,表中的每一个实体代表一个方法(Method),它的名字叫做选择子(SEL),对应着一种方法实现(IMP)
4.对Runloop的理解,5种运行模式
1.RunLoop是一个接收处理异步消息事件的循环,过程中来处理各种事件(1.触摸,2.UI刷新,3.定时器,4。线程间通信)和消息,从而保持程序持续运行。没有事件处理就睡眠,(节省CPU)提高程序性能
2.他里面的 Mode 主要也是为了分隔开不同的功能,使其功能不受影响
1. kCFRunLoopDefaultMode:App的默认Mode,通常主线程是在这个Mode下运行
2. UITrackingRunLoopMode:界面跟踪 Mode,用于 ScrollView 追踪触摸滑动,保证界面滑动时不受其他 Mode 影响
3. UIInitializationRunLoopMode: 在刚启动 App 时第进入的第一个 Mode,启动完成后就不再使用,会切换到kCFRunLoopDefaultMode
4. GSEventReceiveRunLoopMode: 接受系统事件的内部 Mode,通常用不到
5. kCFRunLoopCommonModes: 这是一个占位用的Mode,作为标记kCFRunLoopDefaultMode和UITrackingRunLoopMode用,并不是一种真正的Mode
5.多线程
1.NSThread :手动开启线程,获得主线程,是否为主线程,阻塞线程,强制退出
2.GCD:会自动利用更多的CPU内核,自动管理线程的生命周期,使用方便且安全
3.NSOperation/NSOperationQueue
4.PThread
*可以取消还没执行的线程,正在执行的线程是没有办法取消的
1,NSOperation拥有更多的函数可用,具体查看api。
2,在NSOperationQueue中,可以建立各个NSOperation之间的依赖关系。
3,有kvo,可以监测operation是否正在执行(isExecuted)、是否结束(isFinished),是否取消(isCanceld)。
4,NSOperationQueue可以方便的管理并发、NSOperation之间的优先级。 GCD主要与block结合使用。代码简洁高效。 GCD也可以实现复杂的多线程应用,主要是建立个个线程时间的依赖关系这类的情况,但是需要自己实现相比NSOperation要复杂。
具体使用哪个,依需求而定。 从个人使用的感觉来看,比较合适的用法是:除了依赖关系尽量使用GCD,因为苹果专门为GCD做了性能上面的优化。
*线程执行完即销毁,加入到runloop中就不会被销毁
6.线程安全问题
一块资源可能被多个线程共享,当多个线程访问同一对象,会存在问题(大麦购票订单)
1.互斥锁 @synchronized(锁对象) {// 锁定目标 } 或者 NSLock锁
2.原子性和非原子性。atomic为setter方法加锁,线程安全但是需要消耗大量资源 nonatomic不会为setter方法加锁,非线程安全,适合内存小的移动设备(开发常用)
*所有属性都声明为nonatomic,尽量避免多线程抢夺同一资源,尽量将加锁 资源抢夺的业务逻辑交给服务端处理,以实现轻客户端为目的
*1.加锁的代码尽可能的少2.添加OC对象必须在多个线程是同一个对象
3.UIKit框架都是线程不安全的,为了安全会导致资源占用过大和效率下降,所以UI操作都放在主线程
7.网络七层 (客户端四层)
7.应用层:1.负责传送数据发送请求,按照协议封装成对应数据。2.负责接收数据响应请求,把数据按照应用的标准格式进行解析
6.表示层:数据转换层。1.负责传送数据发送请求时,会将应用层数据转换成网络通用格式。2.负责接收数据响应请求,将会话层传入的网络通用格式转换为对应设备的数据
5.会话层:负责网络通信的建立和断开,连接方式等。1.负责传送数据请求时,把表示层按照规律和标准进行拆分。2.负责接收数据响应时,会把流数据根据每个节点进行完整拼接
4.传输层:主要负责建立两端节点的通信关系,保证数据安全 ( TCP协议)
3.网络层:将数据传输到目标地址,目标地址可以是多个。该层主要是寻找地址和路由选择
2.数据链路层:负责物理层上的通信传输,把0,1序列化有意义的数据帧传给对端
1.物理层:负责将机器语言的0,1转换为电压高低,脉冲光的闪灭输出给物理的传输介质
*客户端:
1.应用层:应用程序间沟通的层,如简单电子邮件传输(SMTP)、文件传输协议(FTP)、网络远程访问协议(Telnet)等。
2.传输层:在此层中,它提供了节点间的数据传送,应用程序之间的通信服务,主要功能是数据格式化、数据确认和丢失重传等。如传输控制协议(TCP)、用户数据报协议(UDP)等,TCP和UDP给数据包加入传输数据并把它传输到下一层中,这一层负责传送数据,并且确定数据已被送达并接收。
3.互连网络层:负责提供基本的数据封包传送功能,让每一块数据包都能够到达目的主机(但不检查是否被正确接收),如网际协议(IP)。
4.网络接口层(主机-网络层):接收IP数据报并进行传输,从网络上接收物理帧,抽取IP数据报转交给下一层,对实际的网络媒体的管理,定义如何使用实际网络(如Ethernet、Serial Line等)来传送数据。
8.TCP/IP的三次握手和四次挥手
三次握手
1.首先客户端向服务端发起一个建立连接的同步(SYN)请求(同步已发送状态)
2.服务端在收到这个请求后向客户端回复一个同步/确认(SYN/ACK)的应答(同步收到状态)
3.客户端收到应答回应后再向服务端发送一个确认(ACK),此时TCP连接成功建立(已建立连接状态)
*最后一次确认
主要防止 已失效的连接请求报文突然又传到服务器上,从而产生错误
四次挥手
1.首先客户端发送终止(FIN)消息给服务端,客户端进入终止等待状态
2.接着服务端收到终止(FIN)后,发送一个ACK给客户端,确认序号为收到序号+1.服务端进入关闭等待状态
3.服务端在回复完客户端TCP断开请求后,不会马上断开,会保证断开前所有数据传输完毕。传输完成会发送一个FIN消息给客户端,服务端进入最后确认状态
4.最后客户端收到FIN消息后,进入时间等待状态,接着发送一个ACK给服务端,确认序号为收到序号+1,服务端进入关闭状态,完成四次挥手
TCP 和 UDP 的区别
1.TCP为传输控制层协议,为面向连接 可靠的 点到点的通信
2.UDP为用户数据报协议,非面向连接 不可靠 点到多点的通信
3.TCP侧重 可靠传输,UDP侧重 快速传输
9.socket 套接字
1.本质就是两个程序双向通信。浏览器进程与web服务器通信,即时通讯进程与服务器进程通信,都得靠socket
10.IOS本地数据持久化
1.NSUserDefaults:可用于存储基本信息,敏感信息不建议存储,因为其安全性几乎为0
*1.不支持存储自定义对象 2.存储的数据是不可变的 3.不是即时写入,需要强制立即写入
2.plist:用于存储程序中经常用到且数据量小而不经常改动的数据。也不支持自定义对象存储
3.keychain:本地重要数据存储,加密安全,删除app后再重装依然可用
4.归档:可以是对象归档,文件是保密的,在磁盘中无法查看,更加安全。遵守NSCodeing协议
5.沙盒写入:持久化在Document目录下,一般存储非机密数据。音乐,视频,图片推荐使用沙盒存储
6.数据库:CoreData 和 FMDB 适合存储量大的数据。(FMDB是以OC的方式封装了SQLite的C语言API)
11.常用的设计模式
1.代理模式:优势是解耦合。敏捷原则:开放-封闭原则。案例:tableview 和 自定义代理
2.观察者模式:优势是解耦合。敏捷原则:接口隔离原则,开放-封闭原则。案例:Notification通知中心 和 KVO
3.MVC模式:优势是使系统 层次清晰 职责分明 易于维护。敏捷原则:对扩展开放-对修改封闭。案例:常用且古老的架构设计(演变:MVVM,MVP)
4.单例模式:确保程序运行期某个类,只有一份实例,一般用于进行资源共享控制。优势:使用简单,延时求值,易于跨模块。敏捷原则:单一职责原则。案例:UIApplication
5.策略模式:优势:使算法的变化独立于使用算法的用户。案例:把类中易变化的抽离出来
6.工厂模式:优势:易于替换,面向抽象编程。案例:项目初期 或 项目小不适合用,(代码复杂度,层次,内存负担 都是增加的)
*iOS设计模式的六大设计原则 (组件化,模块化 的重要性)
1.单一职责:复杂度降低,可读性增强,可维护性增强,变更引起的风险降低
2.开放关闭原则:实现具有抽象性,需要对业务具有前瞻性。从而设计一个具有稳定 灵活的工具类
3.接口隔离:两个类的关系保持最小接口,避免过分依赖
4.依赖倒置:就是高层模块不应该直接依赖底层模块,需要抽象出中间类来实现上下通信
5.里氏替换:为了实现代码共享和重用性等,业务子类继承公共工具父类。缺点继承入侵性强,降低灵活性耦合性增强
6.迪米特法则:类与类间做到最小依赖,还是不要直接以来,抽象出中间层处理。
12.socket连接 和 HTTP连接的区别
1.HTTP协议是基于TCP的,应用层协议,主要解决如何包装数据。socket是对TCP/IP的封装,socket本身并不是协议,而是一个调用接口,通过socket才能使用TCP/IP协议
2.HTTP连接:短连接,客户端向服务器发送一次请求,服务器响应后连接断开,节省资源。服务端不能主动给客户端响应(除非采用HTTP长连接技术)
3.Socket:长连接,客户端跟服务端直接使用Socket进行连接,没有规定连接后断开,因此客户端和服务端保持连接通道,双方可主动发送数据。(一般用于游戏,默认连接超时30s,默认大小8K)
13.weak释放自动被置为nil的实现原理
runtime维护着weak的Hash表,在对象被回收时,会最终触发下面的方法将所有weak指针的值设为nil,涉及到hash表的增删改查,有一定的性能开销
1.释放发生了什么:释放时,调用clearDeallocating函数。clearDeallocating函数首先根据对象地址获取所有weak指针地址的数组,然后遍历这个数组把其中的数据设为nil,最后把这个entry从weak表中删除,最后清理对象的记录
https://www.jianshu.com/p/b93d61418f17
14.HTTPS的加密原理
1.服务端用非对称加密(RSA)生成公钥和私钥
2.然后把公钥发给客户端,服务端则保存私钥
3.客户端拿到公钥后生成密钥
4.然后客户端用公钥对密钥进行加密后发给服务端
5.服务端拿到客户端发来的密钥后,再使用私钥解锁密钥,双方就获得了通信的钥匙
15.SDWebImage加载图片逻辑
1.先在SDWebImageCache中查找是否有对应的缓存,以url为索引先在内存找是否存在
2.如果缓存没有找到就利用通过MD5处理过的Key去磁盘中查找
3.如果磁盘中也没找到,那就去请求下载图片
*整个过程都是在子线程中执行的
16.性能优化
1.使用复用机制
2.尽可能设置View不透明
3.避免臃肿的XIB
4.不要阻塞主线程
5.图片尺寸匹配 imageview
6.View的复用和懒加载机制
7.图形绘制
8.减少离屏渲染(圆角及复杂圆角 阴影 抗锯齿 遮罩等)
9.优化tableview (复用,缓存高度,花了呼哨的效果少用,cell的停止后渲染)
10.启动时间,包大小,冗余代码等
启动优化策略:删除无用库和废弃代码,压缩图片删除无用图片。梳理业务逻辑将加载逻辑进行优化
17.进程线程的区别,同步异步,并发并行
1.进程有独立的地址空间,崩溃后不会影响其他进程。线程没有独立地址空间,一个崩溃后就等同于整个进程死掉
2.同步是顺序执行,异步是彼此独立
3.并发相当于一个人同时做两个以上的事儿,并行相当于两个以上的事儿交给1个人来做
*进程间通信:消息传递系统,管道通信系统(互斥,同步,是否存在)等
*子线程为什么不回调:没有加入Runloop,执行完就销毁
18.断点续传
1.从HTTP1.1开始的,在header中携带两个参数,分别是客户端请求发送的Range 和 服务端返回的Range,在这儿之内是被下载的
19.PING协议
1.是TCP/IP协议族的子协议,用于在IP主机,路由器之间传递控制消息
拓展:是检查网络是否通畅或者网络连接速度。利用网络上机器IP地址的唯一性,给目标IP地址发送数据包,再要求对方返回同样大小的数据包,来查看连通性和时延性
20.NSDictionary 底层原理
NSDictionary(字典)是使用 hash表来实现key和value之间的映射和存储的
https://www.jianshu.com/p/2fd9680b46f6
21.autoreleasepool 场景和原理
1.autoreleasepool 贯穿app的整个周期
2.autoreleasepool 是一种机制,实现了放入其中的对象,可以在生命周期结束后自动(runloop迭代结束)进行释放
autorelease
22.IOS 常见的编码方式
1.MD5:是从一段字符串中通过相应特征生成一段32位的数字字母混合码。不可逆
2.Base64:将二进制的字节序列数据编码成ASCII字符序列构成的文本
3.HMAC加密
4.对称加密 (DES、3DES、AES :相同钥匙,不安全)和 非对称加密(RSA:公钥 和 私钥)
23.layoutIfNeeded和setNeedsLayout的区别
1.layoutIfNeeded 不一定会调用layoutSubviews方法
2.setNeedsLayout 一定会调用layoutSubviews方法(有延迟,在下一轮runloop结束前)
3.如果想在当前runloop中立即刷新,调用顺序应该是
[self setNeedsLayout];
[self layoutIfNeeded];
24.分类和扩展的区别
1.如一个类的方法不能满足我现在的要求,而又不想修改原类的结构,这是分类(category)就有很大的作用。而扩展可以看作是一种特殊的分类
2.分类:分类中只能添加“方法”,不能增加成员变量;分类中可以访问原来类中的成员变量
3.扩展:扩展(extension)可以看作是分类的一个特例(匿名分类)。和分类不同,类扩展即可以声明成员变量又可以声明方法;类扩展中添加的新方法,一定要实现,分类中则没有这种限制
25.atomic 实现机制
1.给setter和getter加锁,经过他俩安全,出了他俩,多线程安全就靠外面代码保障了
2.多线程下将属性设置为atomic可以保证读取数据的一致性,保证数据只能被一个线程占用。会使用自旋锁锁住该属性,不允许其他的线程对其进行读取操作
3.缺点:因为它要使用自旋锁锁住该属性,因此它会消耗更多的资源,性能会很低。要比nonatomic慢20倍
26.对象,类对象,元类,根元类结构体的组成和关联
对象isa指向类对象,
类对象的isa指向元类,还有superclass,方法,属性,协议列表,以及成员变量的描述。
元类isa指向根元类。
根元类的isa指针指向自己,superclass指针指向NSObject类
*实例对象结构体只有一个isa变量,指向实例对象所属的类。
*所有的对象调用方法都是一样的,没有必要存在对象中,对象可以有无数个,类对象就有一个所以只需存放在类对象中
27.IOS 内省 4种方法
1.isKindOfClass,判断是否是这个类或者这个类的子类的实例
2.isMemberOfClass,判断是否是这个类的实例
3.respondsToSelector,判读实例是否有这样方法
4.instancesRespondToSelector,判断类是否有这个方法
28.App 网络层有哪些优化策略
1、优化DNS解析和缓存
2、网络质量检测(根据网络质量来改变策略)
3、提供网络服务优先级和依赖机制
4、提供网络服务重发机制
5、减少数据传输量
6、优化海外网络性能
实践
每个网络绑定到vc,vc销毁,网络请求销毁。
数据请求优先级高于图片请求。网络层做区分。
29.静态库 和 动态库 区别
静态链接是指将多个目标文件合并为一个可执行文件,直观感觉就是将所有目标文件的段合并。需要注意的是可执行文件与目标文件的结构基本一致,不同的是是否“可执行”。
静态库:链接时完整地拷贝至可执行文件中,被多次使用就有多份冗余拷贝。
动态库:链接时不复制,程序运行时由系统动态加载到内存,供程序调用,系统只加载一次,多个程序共用,节省内存。
1.cd到对应的framework目录下,file 库文件,有dynamic 是动态。否则是静态
2.静态库:.a 和 .framework 动态库:.dylib 和 .framework
30.链表和数组的区别,时间复杂度
1.数组静态分配内存,链表动态分配内存
2.数组在内存中连续,链表不连续
3.数组元素在栈区,链表元素在堆区
*数组利用下标定位,时间复杂度为O(1),链表定位元素时间复杂度O(n)
*数组插入或删除元素的时间复杂度O(n),链表的时间复杂度O(1)
31.哈希表
1.采用散列技术将记录存储在一块连续的存储空间中,这块连续的存储空间称为哈希表。所得的存储地址称为哈希地址或散列地址
2.散列技术是指在记录的存储位置和它的关键字之间建立一个确定的对应关系f,使每一个关键字都对应一个存储位置。我们把这种对应关系f 称为散列函数或哈希函数
32.KVO的具体实现
当观察某对象 A 时,KVO 机制动态创建一个对象A当前类的子类,并为这个新的子类重写了被观察属性 keyPath 的 setter 方法。setter 方法随后负责通知观察对象属性的改变状况
问题:
1.view去找viewcontroller
UIView 类继承于 UIResponder,通过 UIResponder 的next 方法来获取 UIViewController。
如果 next 返回是空,则继续向上遍历 superview 并再次使用 next 方法获取。这样一直找下去,直到找到或抛出异常。
2.IOS捕获崩溃日志
联调的时候,用XCode工具(模拟器)找到想要的日志
线上:去appstore 找到TF包的奔溃日志。 或 使用苹果提供的API 来获取崩溃日志 或三方库(bugly,友盟) 或集成KSCrash开源组件
3.scrollview 嵌套 tableview
主要是解决 多个手势冲突问题,会影响最上层的tableview的手势
解决:允许手势向下传递并响应多个手势(gesture return YES),设置顶点状态 给个最大位置做限制就可以。
4.AFNetworking 原理
主要是对 NSURLSession 和 NSURLConnection (IOS9.0 废弃)的封装,分为几大类
1.AFHTTPSessionManager:负责发送网络请求,使用最多的类 (内部封装的NSURLSession)
2.AFNetworkReachabilityManager:检测网路状态工具
3.AFSecurityPolicy:网络安全工具,主要针对 HTTPS 服务
4.AFURLRequestSerialization:序列化工具类,基类。上传的数据转换成JSON格式
5.json解析器,XML解析器,万能解析器,反序列化工具
5.深浅拷贝
1.copy:指针拷贝,源对象和副本指向同一对象,引用计数 +1。(自定义对象)使用时先实现NSCopying协议,必须实现方法 copyWithZone 方法,创建不可变副本
2.mutableCopy:内容拷贝,源对象和副本指向两个不同的对象,源对象引用计数不变,副本 +1。(自定义对象)使用时实现NSMutableCoyping协议,创建可变副本
*系统的 容器类和非容器类 对象是有差异的,对于容器类其元素对象始终是指针复制。
6.#import和#include区别
当被include的文件路径不是绝对路径的时候,有不同的搜索顺序
#import与#include的类似,都是把其后面的文件拷贝到该指令所在的地方
#import可以自动防止重复导入
#import <> 用于包含系统文件
#import""用于包含本项目中的文件
#import, 告诉编译器找到并处理名为Foundation.h文件,这是一个系统文件,#import表示将该文件的信息导入到程序中
7.IOS内存管理机制
iOS内存管理机制的原理是引用计数,当这块内存被创建后,它的引用计数+1,表示有一个对象或指针持有这块内存,拥有这块内存的所有权,如果这时候有另外一个对象或指针指向这块内存,那么为了表示这个后来的对象或指针对这块内存的所有权,引用计数1->2,之后若有一个对象或指针不再指向这块内存时,引用计数-1,表示这个对象或指针不再拥有这块内存的所有权,当一块内存的引用计数变为0,表示没有任何对象或指针持有这块内存,系统便会立刻释放掉这块内存