美文网首页
技术学习

技术学习

作者: lee_moons | 来源:发表于2020-08-06 10:10 被阅读0次

    一:UI视图方面的问题

    1.数据源同步问题处理
    1.并发访问,数据拷贝
    主线程 : 删除数据 reload
    子线程 : 网络请求,数据解析
    问题: 删除操作之后请求的数据会重新刷新回来
    解决办法 : 记录删除操作,请求完数据后同步删除操作

    2.UIView和CALayer
    1.UIView负责提供内容和触摸事件,参与响应链
    2.CALayer负责显示内容Content
    分工明确 遵守单一职责

    3.UI卡顿的优化
    GPU:异步绘制防止离屏渲染
    CPU:预排版和预渲染,对象的创建销毁全部放在子线程

    异步绘制 : displayLayer方法

    4.离屏渲染
    当我们指定了UI视图的某些属性标记为他在未预合成之前不能用于当前屏幕上显示的时候就会触发离屏渲染
    GPU在当前屏幕缓冲区外再开辟一个缓冲区进行渲染操作

    圆角和masktobounds同时使用的时候回触发离屏渲染
    阴影 光栅化 图层蒙版都会触发

    5.为何要避免离屏渲染
    在触发离屏渲染的时候会增加GPU的工作量,可能导致GPU+CPU的工作总耗时超过了16.7MS 会产生掉帧的问题
    创建新的缓冲区,上下文切换 影响性能

    二:Objective-C语言特性相关问题

    分类和扩展
    1.你用分类做了哪些事
    声明私有方法 分解体积庞大的类文件 framework的私有方法公开化
    2.分类的特点
    运行时决议,可以为系统类添加分类
    3.分类中可以添加哪些内容
    1.实例方法 2.类方法 3.协议 4.属性(没有实例变量.需要通过关联对象实现)
    总结: 1.分类添加的方法可以"覆盖"(效果上) 原类的方法
    2.同名分类方法生效取决于编译顺序
    3.名义相同的分类会引起编译报错
    4.关联对象
    关联对象由一个AssociationsManager管理并在AssociationsHashMap储存
    所有的关联内容都放在一个全局的容器中

    2.扩展可以做的事情
    声明私有属性,声明私有方法,声明私有成员变量
    3.分类和扩展的区别
    扩展编译时决议 只能以声明形式存在,多数情况下存在于.M文件 不能为系统类添加扩展
    分类运行时决议 有声明有实现 能为系统类添加分类

    通知和代理
    通知是使用观察者模式实现用于跨层传递消息的机制

    怎样实现通知机制
    key是add监听的通知名称 value是我们添加的observer
    Observer是一个数组包含多个通知的观察者

    KVO的相关
    1.什么是KVO
    kvo是观察者模式的一种实现
    apple使用了isa-swizzling实现了KVO
    2.KVO的实现是
    系统在使用kvo的时候动态创建一个监听的类的子类
    然后子类重写set方法通过set方法内部调用了
    willChangeValueForKey 以及didChangeValueForKey
    使用setter改变值KVO生效
    使用KVC改变值KVO生效
    成员变量直接修改需要手动添加willChangeValueForKey 以及didChangeValueForKey 才可以生效

    KVC的相关
    setvalue:forkey和 valueforkey流程
    先查找是否有get set方法没有的话去寻找相关的成员变量 都没有的话抛出异常

    三:RUNTIME

    objc_object
    包含 isa_t isa操作相关 弱引用相关 关联对象相关 内存管理相关
    objc_class 继承Objc_object 是一个类对象
    包含Class superClass / cache_t cache / class_data_bits_t bits

    共用体isa_t
    指针型isa isa值代表Class的地址
    非指针型isa isa值的部分代表Class的地址

    消息传递机制


    image.png

    缓存查找实质上是hash查找

    对于已排序的列表使用二分查找算法查找方法对应执行函数
    对于未排序的列表使用一般遍历查找方法对应执行函数

    消息转发机制


    image.png

    method-swizzling


    image.png

    应用场景:开发过程需要对页面进出添加统计信息可以替换viewdidload或者viewwillAppear 然后在替换方法中添加关于统计信息的代码

    runtime动态添加方法 运行时添加
    动态方法解析
    @dynamic
    动态运行时语言将函数决议推迟到运行时
    编译时语言在编译期进行函数决议

    能否向编译后的类增加实例变量 否
    能否向动态添加的类增加实例变量 是

    四.内存管理

    内存区域图


    image.png

    栈区:方法调用
    堆区:通过alloc等分配的对象
    bss:未初始化的全局变量
    data:已初始化的全局变量
    text:程序代码

    问题一:iOS操作系统是怎样对内存进行管理的
    要从场景上入手
    TarggedPointer :对于小对象如NSNumber使用TarggedPointer
    NONPOINTER_ISA:对于64位的采用NONPOINTER_ISA方案处理
    散列表管理 :包括引用计数表和弱引用表

    NONPOINTER_ISAd的内存管理

    arm64架构

    散列表方式

    SideTable()结构

    image.png
    使用多个SideTable储存信息 如果是单个会有效率问题
    所以使用了分离锁提高访问效率
    分离锁可以把表分拆给多个部分操作的时候是并发操作提高了访问效率
    SideTable实际上是一个Hash表
    散列表的数据结构

    1.spinlock_t:自旋锁
    "忙等"的锁 适用轻量访问.
    2.RefcountMap 引用计数
    用指针通过HASH查找对象的引用计数
    引用计数表

    image.png
    weakly_referenced:存储对象是否弱引用 0无1有
    弱引用表weak_table_t
    image.png
    MRC和ARC的区别
    image.png
    image.png
    引用计数管理
    alloc实现

    经过一系列调用,最终调用C函数的 calloc,此时并没有设置引用计数为1但是因为retainCount获取引用计数的操作所以会显示引用计数为1

    retain实现

    通过当前对象指针通过HASH函数计算快速的在SideTables里找到对应的SideTable。之后通过当前对象指针从SideTable当中用HASH查找获取当前对象的引用计数值
    总结:通过俩次hash查找找到当前对象引用计数值并进行加一操作
    引用计数的变量

    release实现

    和retain类似 最后实行减一操作

    retainCount实现

    会定义一个变量并复制为1
    获取到引用计数并进行+=操作。这就是alloc并没有设置引用计数 但是你可以获取到引用计数为1的原因
    dealloc的实现


    image.png
    object_dispose()实现会去实现object_destructInstance()方法
    object_destructInstance的实现
    image.png
    clearDeallocating()的实现
    image.png
    弱引用管理
    问题:关于添加弱引用变量的时候

    可以通过弱引用对象进行HASH算法的计算查找对应的位置

    问题:关于系统是怎样将一个weak变量添加到他对应的弱引用表

    一个被声明为__weak的对象指针经过编译器编译之后会调用Objc_initWeak()方法,然后经过一系列的函数调用最终在weak_register_no_lock()函数中进行弱引用变量的添加,添加的位置是通过弱引用对象进行HASH算法的计算查找对应的位置
    如果查找位置已经有了当前对象所对应的弱引用数组,就将新的弱引用变量添加到数组当中如果没有就重新创建一个弱引用数组并在0号位置添加最新弱引用指针,后面的初始化为0。

    问题:当一个对象被释放或废弃之后weak变量是怎么处理的

    清除weak变量,同时指向为nil

    问题2:内部是怎么处理的了

    当一个对象被dealloc之后,在dealloc之中会调用弱引用清除的相关函数,在函数的内部实现当中会根据当前对象指针查找弱引用表,把当前对象对应的弱引用都拿出来(一个数组),然后遍历数组所有的弱引用指针并置为nil

    自动释放池
    问题:什么是自动释放池/自动释放池的实现结构

    自动释放池结构实际上是以栈为结点通过双向链表的形式组合而成的,并且和线程一一对应的.

    image.png
    问题:AutoreleasePool的实现原理是怎样的
    aotureleasePoolPush
    image.png
    image.png
    aotureleasePoolPop

    1.根据传入的哨兵对象找到对应位置
    2.给上次push操作之后添加的对象依次发送release消息
    3.回退next指针到正确位置

    image.png

    释放时机:在当次Runloop将要结束的时候调用AotureleasePoolPage::pop()

    问题:AutoreleasePool为何可以嵌套使用

    多层嵌套调用就是多次插入哨兵对象

    循环引用
    问题:如何破除循环引用

    1.避免产生循环引用
    2.合适的时机手动断开

    问题2:具体的解决方案有哪些

    __weak __block __unsafe_unretained

    __block破解
    image.png
    __unsafe_unretained(不建议使用因为会产生悬垂指针)
    image.png
    怎么解决循环引用的使用示例

    NSTimer
    第一个解决办法:timer置nil

    image.png

    第二个解决办法:添加中间对象


    image.png

    令中间对象持有俩个弱引用变量分别是NSTimer 和原对象 然后在nstimer中直接分派的回调 是在中间对象中实现的.在实现的方法当中对他所持有的target进行值的判断.值存在把NSTimer的回调给原对象,如果值不存在那么设置NSTimer为无效状态

    五:Block

    问题:什么是BLOCK

    block是将函数及其上下文封装起来的对象

    问题:什么是BLOCK调用

    block调用就是函数的调用

    问题:关于BLOCK截获特性,是否了解

    1.对于基本数据类型的截获变量是截取其值
    2.对于对象类型的局部变量连同所有权修饰符(属性关键字)一起截获(或者说强引用)
    3.以指针形式截获局部静态变量
    4.不截获全局变量,静态全局变量

    __block修饰符
    问题一:__block作用 __forwarding指针是用来干什么的

    __block修饰的变量都变成了对象
    栈上的__forwarding指针是指向自身的
    进行COPY之后
    栈上的__forwarding指针是指向堆上的__forwarding而堆上的__forwarding指针是指向自身的


    image.png
    问题二:__forwarding指针存在意义

    不论在任何内存位置,都可以顺利的访问一个__block的变量.

    image.png
    block循环引用

    1.block捕获的变量是当前对象的成员变量而block也是当前对象的成员变量.会造成自循环式的循环引用可以通过添加__weak修饰避免
    2.__block造成的循环引用如下图
    __block为啥会在ARC下循环引用而MRC下没有问题以及规避方法

    image.png
    可以在block内部给__block修饰的对象进行置nil操作断开一个强引用
    弊端:如果不调用block 这个环会一直存在

    六:第三方库相关面试问题

    一 AFNetworking

    image.png
    image.png

    AFURLSessionManager的作用

    • 创建和管理NSURLSession、NSURLSessionTask
    • 实现NSURLSessionDelegate等协议的代理方法
    • 引入AFSecurityPolicy保证请求安全
    • 引入AFNetworkReachabilityManager监听网络变化

    二 SDWebImage

    image.png

    三 ReactCocoa

    rac是一个函数响应式编程的第三方库


    image.png

    问:我们怎么使用订阅


    image.png

    七:多线程

    GCD

    问题一:
    image.png

    由队列引起的循环等待

    问题二:
    image.png
    image.png

    dispatch_async(global_queue) 这个Block会在GCD所维护的线程池中某个线程上去执行处理,这些线程池默认是没有RUNLOOP的 而performSelector 方法 是提交任务到RUNLOOP上的 所以无法执行

    问题三:怎样利用GCD实现多读单写
    image.png
    image.png
    问题三:

    NSOperation

    问题一:优势和特点

    1.添加任务依赖
    2.任务执行状态的控制
    3.控制最大并发量

    问题二:NSOperation的状态

    isReady isExecuting(是否正在执行中) isFinished isCancelled

    问题三:我们应该怎样控制NSOperation的状态

    (主要看是不是重写了:NSOperation的main方法和start方法)
    如果重写main方法,底层控制变更任务完成执行状态,以及任务退出。(我们不需要操作)
    如果重写start方法,自行控制任务状态

    NSThread

    image.png
    问题一:NSThread执行原理

    内部创建了一个p_thread线程,当我们的main函数或者我们指定的target selector方法执行结束之后,系统会为我们进行线程的退出管理操作。如果我们想要维护一个常驻线程需要在NSThread所对应的selector方法中去维护一个Runloop事件循环

    问题一.你都用过哪些锁?结合实际谈谈如何使用的
    @synchronized

    一般在创建单例对象的时候使用,保证多线程环境下创建的对象是唯一的

    atomic

    修饰属性的关键字
    对被修饰对象进行原子操作(不负责使用)


    image.png
    OSSpinLock

    循环等待访问,并不释放当前资源
    用于轻量级数据访问,比如简单的Int +1 / -1操作

    NSLock
    image.png

    可以使用NSRecursiveLock(递归锁)解决上述问题

    dispatch_semaphore_t(信号量)
    image.png
    image.png
    image.png

    多线程问题总结

    问题1.iOS系统为我们提供的几种多线程技术各自的特点是什么

    GCD:实现简单的线程同步包括:1.子线程分派 2.多读单写
    NSOperation:方便我们对任务的状态进行控制,可以添加移除依赖
    NSThread:基本用于创建一个常驻线程

    问题2.NSOperation对象在Finished之后是怎样从queue当中移除掉?

    会使用KVO的方式通知queue达到了移除对象的目的

    八:RUNLOOP

    image.png
    问题一:什么是RUNLOOP

    RUNLOOP是通过内部维护的事件循环来对事件/消息进行管理的一个对象

    问题二: 什么是事件循环

    维护的事件循环可以用来处理消息或者事件对他们进行管理,同时在没有消息需要处理时,会从用户态发生一个到内核态的切换,由此可以实现当前线程的休眠.避免资源占用,同时在有消息需要处理时,会从内核态发生一个到用户态的切换,由此可以实现唤醒当前线程


    image.png
    问题二:main函数为什么能保持不退出

    因为UIApplicationMain函数内部会启动主线程的一个Runloop,而Runloop他又是对事件循环的维护机制,有事做事没事会从用户态发生一个到内核态的切换.

    RUNLOOP的数据结构

    image.png
    CFRunLoop:

    包括
    pthread 一一对应关系 (和RUNLOOP)
    currentMode ------- CFRunLoopMode
    modes ------- NSMutableSet<CFRunLoopMode *>
    commonModes ------- NSMutableSet<NSString *>
    commonModeItems ------- observe timer source

    image.png
    source0:需要手动唤醒线程
    source1:具备唤醒线程的能力
    CFRunLoopTimer:基于时间的定时器,和NSTimer是toll-free bridged(免费桥转换)的
    CFRunLoopObserver:观测时间点
    • kCFRunLoopEntry: RunLoop准备启动时
    • kCFRunLoopBeforeTimers:RunLoop将要对Timer相关事件进行处理的时候
    • kCFRunLoopBeforeSoureces:将要处理source事件
    • kCFRunLoopBeforeWaiting:通知对应观察者当前RunLoop将要进行休眠
    • kCFRunLoopAfterWaiting:内核态切换到用户态之后不久
    • kCFRunLoopExit: RunLoop退出的通知
    问题:RunLoop和mode以及他所对应的source time observer是怎样的关系

    一对多的关系


    image.png
    问题:RunLoop为什么有多个mode

    为了起一个屏蔽的效果,屏蔽其他Mode的影响

    CommonMode

    image.png

    事件循环的实现机制

    问题:我们的程序从点击一个图标到程序启动到最终被杀死这一过程系统是怎样实现的?

    void CFRunLoopRun()

    问题:当一个处于休眠状态的RunLoop我们可以用哪些方式来唤醒
    image.png
    image.png
    image.png

    RunLoop与多线程是什么关系

    线程是和RunLoop一一对应的
    自己创建的线程默认是没有RunLoop的

    问题:怎样实现一个常驻线程
    image.png
    image.png
    image.png

    RunLoop面试总结

    问题一:什么是RunLoop,它是怎样做到有事做事,没事休息的?

    是由于我们在调用CFRunLoopRun()相关方法之后会调用系统的一个函数mash_message ,会从用户态发生一个到内核态的切换,由此可以实现当前线程的休眠.所以做到有事做事没事休息

    问题二:怎样保证子线程数据回来更新UI的时候不打断用户的滑动操作

    可以通过把子线程抛回给主线程进行UI更新的这块逻辑包装起来提交到主线程的default模式下面,而滑动的时候mode切换为UITrackingRunLoopMode。分派到default模式下的任务就不会执行,而手停止滑动时候当前mode切换到default模式下面,这时候会处理子线程上抛的任务。 就不会打断用户的滑动操作

    九:网络

    image.png

    HTTP

    问题一:你是怎样理解HTTP的,HTTP协议包含哪些内容了

    超文本传输协议

    • 请求/响应报文
    • 连接建立流程
    • HTTP的特点
    请求/响应报文
    image.png
    image.png
    问题二:HTTP的请求方式

    GET POST HEAD PUT DELETE OPTIONS

    问题三:GET和POST请求方式的区别

    GET请求参数以?分割拼接到 URL后面,POST请求参数在Body的里面
    GET参数长度限制是2048个字符,POST一般没有该限制
    GET请求不安全,POST比较安全(初级回答)
    实际应该从语义的角度来回答 | 语义:指的是协议的一个定义规范
    GET一般用于获取资源:具有安全的,幂等的,可缓存的特性;
    POST一般用于处理资源:具有非安全的,非幂等的,不可缓存的特性

    安全性:不应引起Server端的任何状态变化

    GET HEAD OPTIONS都是具备安全性的

    幂等性:同一个请求方法执行多次和执行一次的效果完全相同

    PUT DELETE GET

    可缓存性:请求是否可以缓存

    HEAD GET

    连接建立流程

    image.png

    HTTP的特点

    • 无连接 (由HTTP的持久链接进行补偿)
    • 无状态(引出Cookie/Session技术)
    持久链接
    image.png
    问题一:为什么HTTP提供了持久链接这个方案

    为了提升网络请求访问的效率.

    头部字段
    • Connection : keep-alive(客户端希望使用持久链接)
    • time:这次持久链接(TCP链接)需要在多长时间内有效
    • max:这条链接最多可以发生多少个http请求
    怎样判断一个请求是否结束
    • Content-length : 1024 (客户端可以根据所接受数据的字节数是否达到这个值,达到了就说明我们这条HTTP请求的响应已经全部接收,意味着请求结束了)
    • chunked : 当有多个块通过HTTP的TCP连接传输给客户端的时候,每个报文都带有chunked字段,而最后一个块的chunked是个为空的值,可以根据此判断是否请求结束.
    Charles抓包原理是怎样的
    • 利用中间人攻击这个漏洞来实现的

    HTTPS与网络安全

    HTTPS和HTTP有怎样的区别
    image.png
    HTTPS连接的建立流程是怎样的
    image.png
    会话秘钥

    会话秘钥 = random S + random C + 预主秘钥

    HTTPS都使用了哪些加密手段?为什么?
    • 连接过程中使用的非对称加密,比较耗时!
    • 后续通信过程要使用对称加密
    非对称加密
    image.png
    对称加密
    image.png
    TCP/UDP
    image.png
    UDP特点
    • 无连接
    • 尽最大可能交付
    • 面向报文: 既不合并也不拆分


      image.png
    UDP功能
    • 复用
    • 分用
    • 差错检测
    复用和分用
    image.png
    差错检测
    image.png
    TCP(传输控制协议)
    特点
    • 面向连接 :
      数据传输开始之前,需要建立连接 三次握手 数据传输结束之后,需要释放连接 四次挥手
    • 可靠传输
    • 面向字节流
    • 流量控制
    • 拥塞控制
    问题一:为什么要进行三次握手?

    为了解决同步请求连接建立的报文超时的场景,规避这些连接建立产生的异常。

    问题二:为什么要进行四次挥手?
    可靠传输

    无差错/不丢失/不重复/按序到达
    停止等待协议
    无差错情况/超时重传/确认丢失/确认迟到

    流量控制

    滑动窗口协议


    image.png

    接收窗口通过向TCP的报文首部字段去更改窗口值来调整发送方的发送速率的

    流量控制

    慢开始,拥塞避免
    快恢复,快重传

    TCP的慢启动特性:如下图
    image.png

    横轴:交互次数 纵轴:窗口值的大小

    DNS解析

    image.png
    image.png
    image.png
    DNS解析存在哪些常见问题
    - DNS劫持问题
    image.png
    DNS劫持和HTTP的关系是怎样的?

    毫无关系的 因为DNS解析发生在HTTP连接建立之前的,DNS解析请求使用UDP数据报,端口号53

    怎么解决DNS劫持

    1.httpDNS
    将使用DNS协议向DNS服务器的53端口进行请求
    变为使用HTTP协议向DNS服务器的80端口进行请求


    image.png

    2.长连接


    image.png
    - DNS解析转发问题
    image.png
    Session/Cookie
    image.png
    什么是Cookie

    Cookie主要用来记录用户状态,区分用户;状态保存在客户端


    image.png

    客户端发送的Cookie在http请求报文的Cookie首部字段中
    服务端设置的http响应报文的Set-Cookie首部字段

    怎样修改Cookie
    • 新Cookie覆盖旧Cookie
    • 覆盖规则: name path domain等需要与原cookie一致
    怎样删除Cookie
    • 新Cookie覆盖旧Cookie
    • 覆盖规则: name path domain等需要与原cookie一致
    • 设置Cookie的expires=过去的一个时间点,或者maxAge = 0
    怎样保证Cookie的安全
    • 对Cookie进行加密处理
    • 只在https上携带Cookie
    • 设置Cookie为httpOnly,防止跨站脚本攻击
    什么是Session

    Session主要用来记录用户状态,区分用户;状态保存在服务端

    Session和Cookie的关系
    • Session需要依赖Cookie机制
    Session工作流程
    image.png

    十:设计模式

    六大设计原则

    • 单一职责原则
      一个类只负责一件事,比如UIView和CALayer
    • 开闭原则
      对修改关闭,对扩展开放
    • 接口隔离原则
      使用多个专门的协议,而不是一个庞大臃肿的协议
      协议中的方法尽量少
    • 依赖倒置原则
      抽象不应该依赖于具体实现,具体实现应该依赖于抽象
    • 里氏替换原则
      父类可以被子类无缝替换,且原有功能不受任何影响 (如KVO)
    • 迪米特法则
      一个对象应当对其他对象有尽可能少的了解。高内聚,低耦合

    责任链模式

    image.png

    相关文章

      网友评论

          本文标题:技术学习

          本文链接:https://www.haomeiwen.com/subject/mhafrktx.html