一面问题汇总:
iOS基本知识:
1.OC语言层面,runtime,isa指针,消息机制
2.UI,布局,动画,事件传递和响应链,控制器声明周期
3.多线程,网络
4.copy,KVC,KVO,block,代理,设计模式,优化
5.MVC,MVVM
6.数据持久化,UserDefult,归解档,SQlite(FMDB)
4.三方库,推送APNS,分享
5.cocoapods、git、svn
性能优化:
1.卡顿优化 减少CPU,GPU资源消耗,防止出现离屏渲染
2.耗电优化 网络请求,定位,渲染,I/O,少用定时器
3.启动优化
冷启动三个阶段:
动态链接:装在Mach-O 文件和动态库。减少动态库,类和分类数量
runtime:+load,注册类,初始化类对象
main: 耗时操作不要放在这
4.包大小优化
5.弱网环境优化
屏幕成像原理:CPU负责布局计算,图片格式转换和解码;GPU负责图像的渲染;然后屏幕垂直同步,成像
如果屏幕发起垂直同步,GPU还没有渲染完成,就会造成卡顿。
CPU职责:对象创建和销毁,属性调整,布局计算,文本计算排版,图片解码、绘制、格式转换,
GPU职责:纹理渲染
离屏渲染:GPU有两种渲染模式,当前屏幕渲染和离屏渲染,将离屏缓冲区的渲染结果显示到屏幕上,上下文环境从离屏切换到当前屏幕,这个过程会造成性能的消耗
以下操作会造成离屏渲染:
光栅化,layer.shouldRasterize = YES
遮罩,layer.mask
圆角,同时设置 layer.masksToBounds = YES,layer.cornerRadius > 0
阴影,如果设置了 layer.shadowPath 不会产生离屏渲染
TableView优化
0.cell复用
1.缓存行高
2.延迟加载,在scrollerView中停止滚动的代理方法中添加[self.imageView performSelector:@selector(setImage:) withObject:[UIImage imageNamed:@"tupian"] afterDelay:4.0 inModes:@[NSDefaultRunLoopMode]]
3.切圆角,遮罩,阴影效果会造成离屏渲染
4.减少层级关系,少用透明,减少图片分辨率
block:
block是一个预先准备好的代码块,本质是结构体
分类:
1.全局block 内部没有引用外部变量的 Block
2.栈block block 内部引用外部变量
3.堆block
Block从栈中复制到堆的情况:
调用Block的copy实例方法时
Block作为函数返回值返回时
在带有usingBlock的Cocoa方法或者GCD的API中传递Block时候
将block赋给带有__strong修饰符的id类型或者Block类型时
默认 引用外部变量 引用static变量
类: 全局区; 栈 全局
对象:栈; 堆区 全局
引用外部变量的传递方式:
一般数据类型:值截获
局部静态变量:指针截获
全局变量:直接引用全局变量
__block原理:
__block修饰的变量变成了一个结构体对象,block内部修改的变量是__block修饰变量结构体的成员
forwarding指针是外部变量的被__block修饰后,指向堆结构体的指针
对象类型的外部变量,对象类型的结构体里面多了copy和dispose两个函数
属性修饰区别:
weak,正常使用没有问题,如果重新初始化,不能成功为nil
strong,使用的都是同一块内存地址,一个地方改变,全变
copy 不能改变,但是能够重新赋值,初始化,但都为不可变
copy:
runtime:
runtime是OC动态性的基础,OC动态性是指确定对象的类型和方法实现是在运行时实现的,可以在运行时动态的指向别的类,进行消息传递和转发
可以在程序运行的时候动态的创建类和对象,和方法实现
runtime其实就是把编译期做的决定推迟到运行期,在运行的时候才去检查对象的所属类和方法实现,利用这一特性在运行时动态改变对象的类型和方法实现
对象消息转发的过程:
0.对象通过isa指针找到他的所属类(对象内只存有一个isa指针,目的是减少内存,类中也有一个isa指针指向元类,元类中存放类方法,元类也有继承关系)
1.去当前类的缓存方法列表中找
2.去当前类的方法别表中找
3.去父类的方法列表中找,如果没有,一直找到根类
4.根类再找不到,走动态解析(add_method)和消息转发(看别的类能否处理这个消息)
5.没有,抛出错误unrecognize selector
如何实现weak变量的自动置为nil功能?
runtime在注册和初始化一个类时,当一个属性被修饰为weak时,会将weak变量指向的地址作为value放入一张Hash表中,将weak变量的作为key。这样形成一个key-value的键值对,当引用计数变为0的时候,系统通过key-value查找指向weak变量的地址,将变量赋值为nil
内存5大分区:
1.堆区 动态分配内存
2.栈区 系统管理内存
3.静态区 已经初始化的全局变量和静态变量
4.bss段 未初始化的全局变量和静态变量
5.代码区 程序运行时产生的二进制数据
runloop:
处理事件的循环。状态:接受消息,恢复,处理,休眠
分类:source,observe,timer
应用:1.NSThread用runloop实现线程常驻 2.NSTimer 3.imageView推迟显示
KVO:
观察者模式的一种实现
原理:在运行时创建监听对象当前类的子类,并为这个新的子类重写了被观察属性 keyPath 的 setter 方法。setter 方法负责通知观察对象属性的改变,被观察对象的 isa 指针从指向原来的类,变为指向新建的子类
数组add不会触发KVO,没有走set方法
KVC:
键值编码(Key-Value Coding),一个非正式的 Protocol,使用字符串(键)访问一个对象实例变量的机制。而不是通过调用 Setter、Getter 方法等显式的存取方式去访问。
多用于访问系统私有属性,字典和模型的互相转换
category:
作用:
1.通过分类来为已知的类扩展方法和属性
2.通过实现分类的 load 方法来实现 Method Swizzling
3.将一个类拆分成多个实现文件
不能添加属性原因:因为在运行期,对象的内存布局已经确定,如果添加实例变量就会破坏类的内部布局
添加属性:通过关联对象,实现对象绑定。没有实例变量(iVar)
load方法可以继承。调用子类的load方法之前,会先调用父类的load方法,分类中load方法不会覆盖本类的load方法,先编译的分类优先调用load方法
原理:
1.在编译时期,会将分类中实现的方法生成一个结构体 method_list_t 、将声明的属性生成一个结构体 property_list_t ,然后通过这些结构体生成一个结构体 category_t 。
2.然后将结构体 category_t 保存下来
3.在运行时期,Runtime 会拿到编译时期我们保存下来的结构体 category_t
4.然后将结构体 category_t 中的实例方法列表、协议列表、属性列表添加到主类中
5.将结构体 category_t 中的类方法列表、协议列表添加到主类的 metaClass 中
这里需要注意的是:category_t 中的方法列表是插入到主类的方法列表前面(类似利用链表中的 next 指针来进行插入),所以这里 Category 中实现的方法并不会真正的覆盖掉主类中的方法,只是将 Category 的方法插到方法列表的前面去了。运行时在查找方法的时候是顺着方法列表的顺序查找的,它只要一找到对应名字的方法,就会停止查找,这里就会出现覆盖方法的这种假象了。
Extension 和 Category 两种实现模式区别
Extension 是在编译时期实现的,Category是在运行时期决定的
自旋锁和互斥锁的区别
自旋锁会忙等: 所谓忙等,即在访问被锁资源时,调用者线程不会休眠,而是不停循环在那里,直到被锁资源释放锁。
互斥锁会休眠: 所谓休眠,即在访问被锁资源时,调用者线程会休眠,此时cpu可以调度其他线程工作。直到被锁资源释放锁。此时会唤醒休眠线程。
优缺点:
自旋锁的优点在于,因为自旋锁不会引起调用者睡眠,所以不会进行线程调度,cpu时间片轮转等耗时操作。所有如果能在很短的时间内获得锁,自旋锁的效率远高于互斥锁。
缺点在于,自旋锁一直占用CPU,他在未获得锁的情况下,一直运行--自旋,所以占用着CPU,如果不能在很短的时 间内获得锁,这无疑会使CPU效率降低。自旋锁不能实现递归调用。
pthread_mutex 表示互斥锁。互斥锁可以传入不同参数,实现递归锁pthread_mutex(recursive)。NSLock,NSCondition,NSRecursiveLock,NSConditionLock都是内部封装的pthread_mutex,即都属于互斥锁。@synchronized是NSLock的一种封装,牺牲了效率,简洁了语法。
OSSpinLock 表示自旋锁,从上图可以看到自旋锁的效率最高,但是现在的iOS因为优先级反转的问题,已经不安全,所以推荐使用pthread_mutex或者dispatch_semaphore
aotomic为什么是不安全的
存取能保证数据完整性,但是多线程下读取的数据不确定
atomic所说的线程安全只是保证了getter和setter存取方法的线程安全,并不能保证整个对象是线程安全的
NSTimer:
target可以是weakself,避免循环引用
intstancetype id区别
区别1:
在ARC(Auto Reference Count)环境下:
instancetype用来在编译期确定实例的类型,而使用id的话,编译器不检查类型, 运行时检查类型.
在MRC(Manual Reference Count)环境下:
instancetype和id一样,不做具体类型检查
区别2:
id可以作为方法的参数,但instancetype不可以
instancetype只适用于初始化方法和便利构造器的返回值类型
空指针和野指针
空指针:不指向任何内存地址,赋值为0的指针
野指针:指针指向的内存地址已经被释放的指针
NULL空指针 nil空对象 NSNull一个值为空的对象
链表和数组区别:
链表和数组都属于线性表,线性表分为顺序线性表(数组)和链表,链表分为单向链表,双向链表,循环链表
链表是靠指针连接起来的,内存是不连续的,节点内容是当前节点信息和下一个节点的地址,便于删除和增加元素,
数组在内存中是连续的,便于查找和修改
设计模式:
对象创建:
原型:copy对象
工厂方法:使得类的实例化延迟到其子类。通过不同的工厂生产不同类型的产品,且两个产品类最终返回的是他们的父类
抽象工厂:提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类
生成器:将一个复杂对象的构建与它的表现分离,使得同样的构建过程可以创建不同的表现
单例:保证一个类仅有一个实例,并提供一个访问它的全局访问点
接口类:
适配器:将一个类的接口转换成客户希望的另一个接口,适配器模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。
桥接:将抽象部分与它的实现部分分离,使它们都可以独立地变化。
外观:为系统中的一组接口提供一个统一的接口。外观顶一个高层接口,让子系统更易于使用
对象去耦:
中介者:用一个对象来封装一系列对象的交互方式,中介者使各对象不需要显示地相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互。UINavigationController
观察者:定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并自动更新。 KVO
抽象集合:
组合:将对象组合成树形结构以表示“部分-整体”的层次结构。组合使得用户对单个对象和组合对象的使用具有一致性
迭代器:提供一种方法顺序访问一个聚合对象中的各个元素,而又不需要暴露该对象的内部表示
行为扩展:
访问者:
装饰:动态地给一个对象添加一些额外的职责。就扩展功能来说,装饰模式相比生成子类更为灵活 category
责任链:使多个对象都有机会处理请求,从而避免请求的发送者和接受者之间发生耦合。此模式将这些对象连成一条链,并沿着这条链传递请求,直到有一个对象处理它为止。 hit-test 事件响应链
swift和OC区别
swift是静态语言,元组,方法重载,高阶函数,可选值,函数式编程,面向协议编程,更安全
OC动态语言
swift逃逸闭包和非逃逸闭包
默认非逃逸闭包,逃逸闭包生命周期比函数长,为了保证调用self不为nil,所以需要强引用,避免循环引用
class和struct区别
struct值类型,创建更快,占用内存空间小,struct的方法要去修改property的值,要加上mutating,class则不需要。
class引用类型,成员必须初始化,可继承
ISO网络七层模型:物理层,数据链路层,网络层,传输层,表示层,会话层,应用层
TCP/IP参考模型:物理层,数据链路层,网络层,传输层,应用层
传输层协议:
TCP:可靠传输,链接需要三次握手,断开需要四次挥手
UDP:不可靠传输
HTTP:建立在TCP基础上的应用层协议。
报文格式:
请求:
请求行:请求方法,URL,HTTP版本号
请求头:Host,User-Agent,Content-Type,Content-Length,Accept,Accept-Language,Accept-Encoding,Cookie,Connection(是否长连接)
请求体:GET请求请求体为空
响应:
状态行:HTTP版本号,状态码(100临时响应,200成功,300重定向,400客户端错误,500服务端错误)
响应头:Server,Age(响应持续时间),Set-Cookie,Connection,
响应体
WebSocket 是一种双向通信协议。iOS一般用SocketRocket
原生JS交互
JS调原生:
- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message;中执行
- (void)addScriptMessageHandler:(id
原生调JS:- (void)evaluateJavaScript:(NSString *)javaScriptString completionHandler:(void (^ _Nullable)(_Nullable id, NSError * _Nullable error))completionHandler;
webview请求相机功能
本地通知原理:
多线程通知,接收通知的方法所在线程是由发送通知的线程决定的。子线程发送通知接收通知的方法在子线程,如果需要UI操作需要回到主线程
Universal Link:
iOS9推出,域名必须是HTTPS,不用打开浏览器直接跳转应用,也可用于应用之间的跳转,没安装应用则打开网页,只有当前webview的url域名,与跳转目标url域名不一致时,Universal Link 才生效。
配置:
1.在域名根目录下配置json文件,包含APPID和path
2.在苹果后台打开Assocaiated Domains功能
3.在XCode中配置Assocaiated Domains域名
音视频相关:
视频音频格式,FFmpeg
断点续传
快速打包方式:
fastlane
jenkins
编译器架构:
传统:前端,优化器,后端
iOS:前端(Clang),LLVM(Bitcode是LLVM编译器的中间代码的一种编码),后端
算法:
二分法
快排
爬楼梯