美文网首页
2021-06-19

2021-06-19

作者: TAsama | 来源:发表于2022-06-13 16:50 被阅读0次

    UI试图相关问题

    大纲

    • UITableView 相关
    • 事件传递&视图响应
    • 图像显示原理
    • 卡顿&掉帧
    • 异步绘制&绘制原理
    • 离屏渲染

    重点:

    1、重用机制
    2、并发访问,更新数据(1、子线程同步主线程的操作2、多线程操作同步到串行队列执行)
    3、传递和响应(传递由上到下,响应由下往上)
    4、图像显示原理

    • CPU 处理布局,绘制,图像编解码,提交位图
    • GPU 渲染管线(顶点着色,图元装配,光栅化,片段着色,片段处理)

    5、处理UI卡顿掉帧的问题

    • 原因 VSync信号来临时,GPU中不能提交相应画面数据(未处理完)

    6、异步绘制 实现了layer的delegate方法,即可进行异步绘制displayLayer

    Object-C特性

    大纲

    • 分类
    • 关联对象
    • 扩展
    • 代理
    • 通知
    • KVO
    • KVC
    • 属性关键字

    重点

    分类:

    • 运行时决议
    • 可以为系统类添加分类
    • 添加 1、实例方法 2、 类方法 3、协议 4、属性
    • 最后编译的分类方法优先生效
    • 分类添加的方法“覆盖”原类方法
    • 名字相同的分类会引起编译报错

    关联兑现:

    • 为分类所添加的成员变量不会被添加到宿主类上,而是关联到AssocitationsManager管理(HashMap)

    扩展:

    • 用扩展生命私有属性
    • 用扩展生命私有方法
    • 用扩展生命私有成员变量
    • 编译时决议
    • 只以声明的形式存在
    • 不能为系统类添加扩展

    代理

    • 软件设计模式
    • @protocol
    • 一对一

    通知:

    • 一对多
    • 使用观察者模式实现,用于跨层传递消息的机制

    KVO

    • 观察者模式的一种实现
    • isa混写技术来实现KVO(修改监听对象的isA指针的指向)
    • 手写KVO valueWillChanged、valueDidChanged

    KVC

    • key value coding
    • 先判断有没有属性方法,如果没有,则判断有无实例变量,如也没有则报错

    属性关键字

    • atomic
    • nonatomic
    • assign/week
    • copy

    Runtime

    大纲

    • 数据结构
    • 类对象与原类对象
    • 消息传递
    • 方法缓存
    • 消息转发
    • Method-Swizzling
    • 动态添加方法
    • 动态方法解析

    数据结构

    • objc_object
      结构体: isa_t、关于isa操作相关、弱引用相关、关联对象相关、内存管理相关
    • objc_class
      结构体:suoerClass指针、cache_t cache(方法缓存)、class_data_bits_t(只读信息,协议,属性,方法)
    • method_t
      名称,返回值,参数,函数体
      const char* types => Type Encodings
      返回值 参数1 参数2 ... 参数n
      只读信息中:name 原生方法列表 成员变量 属性 协议
    • 对象、类对象、原类对象(关系)

    消息传递

    void objc_mgsSend(Void /* id self, SEL op, .../)
    void objc_mgsSendSuper(Void /
    struct objc_super super, SEL op, .../)

    消息转发流程

    resolveInstanceMethod: 返回YES 消息处理结束 ,返回NO forwardingargetForSelector: 返回转发目标, 返回nil methodSignatureForSelector: 返回方法签名,返回nil 报错

    Method-Swizzling

    • 方法交换

    动态添加方法

    • class_addMethod: 接受对象,函数名,方法签名

    动态方法解析

    • @dynamic

    内存管理

    大纲

    • 内存布局
    • 内存管理方案
    • 数据结构
    • ARC & MRC
    • 引用计数
    • 弱引用
    • 自动释放池
    • 循环引用

    内存布局

    • 栈(向下增大)
    • 堆(向上增大)
    • 未初始化数据
    • 已初始化数据
    • 代码段

    内存管理方案
    iOS是怎样管理内存的?

    • TaggedPointer
    • NONPOINTER_ISA (非指针型isa)
    • 散列表(弱引用表和引用计数表)

    NONPOINTER_ISA
    散列表

    • SideTavles() 结构 ,是一个哈希表,是一个多张表,可以实现分离锁

    怎样实现快速分流
    使用hash表查找,提高查找效率

    数据结构
    散列表的数据结构

    • Spinlock_t 自旋锁
    • RefcountMap 引用计数表
    • weak_table_t 弱引用表

    Spinlock_t

    • 是一个“忙等”的锁。
    • 适用于轻量访问

    RefcountMap

    • 是一个hashMap
    • 使用hash查找为了提高引用效率

    weak_table_t

    • 是一个hashMap
    • 存储了弱引用对象的指针

    MRC

    手动引用计数

    • alloc 分配内存空间
    • retain 引用计数加一
    • release 引用计数减一
    • retainCount 获取对象的引用计数
    • autorelease 在autoreleasePool结束的时候调用release
    • dealloc 调用super dealloc

    ARC

    自动引用

    • ARC是LLVM和Runtime协作的结果
    • ARC新增了weak、strong属性关键字

    引用计数管理

    alloc实现

    调用了c函数的calloc
    此时并没有增加retainCount为1

    retain

    • 查找对象的SideTable表
    • 从SideTable表中获取当前对象的引用计数值
    • 对引用计数值进行+1操作

    release

    • 查找SideTable
    • 从SideTable表中获取当前对象的引用计数值
    • 对引用计数值进行-1操作

    retainCount

    • 查找SideTable
    • 从SideTable表中获取当前对象的引用计数值
    • 若不存在引用计数,则对引用计数值进行+1操作

    dealloc
    当前对象是否可以直接释放一句以下判断条件

    • nonpointer_isa
    • weakly_referenced
    • has_assoc 是否有关联对象
    • has_cxx_dtor 是否有C++内容,或是否使用arc管理内存
    • has_sidetable_rc 当前对象的引用计数是否通过sidetable表维护的

    以上全部为否才可以调用C函数直接释放
    否则就要调用object_dispose() 进行释放

    object_dispose

    • 开始
    • objc_destructInstance(): c++释放、移除关联对象、将弱引用指针置位nil、清除引用计数
    • c函数free()
    • 结束

    弱引用管理
    添加弱引用变量的流程

    • objc_initWeak()
    • storeWeak()
    • weak_register_no_lock()
      1 通过对象指针hash计算查找
      2 如果已经存在了弱引用数组,则添加
      3 如果没有,则创建弱引用数组

    清除weak变量,同事设置为nil

    • dealloc
    • 。。。
    • weak_clear_no_lock()

    自动释放池

    • runloop将要结束时调用pop操作
    • 多层嵌套就是多次插入哨兵对象
    • 在for循环中alloc创建了较大的内存消耗是,可手动插入autoReleasePool来释放内存对象

    循环引用

    • 自循环引用
    • 相互循环应用
    • 多循环引用

    考点

    • 代理
    • Block
    • NSTimer
    • 大环引用

    如何破除

    • 避免产生
    • 在合适的时机手动破除循环引用

    __weak
    __block(ARC下会被强引用)
    __unsafe_unretained 修饰对象不会增加引用计数,但是会产生悬垂指针

    解决NSTimer的循环引用问题
    NSTimer会被Runloop引用,所以必须手动释放NSTimer来解除引用。
    采用中间对象,同时弱引用NSTimer和对象,当对象被释放后,NSTimer回调后,判断弱引用对象已经释放为nil,此时则invalidate timer,将NSTimer置位nil,此时NSTimer也被成功释放。

    Block

    大纲

    • Blokc介绍
    • 截获变量
    • __block修饰符
    • Block的内存管理
    • Block的循环引用

    Block = 函数 + 上下文 + 对象
    Block截获变量

    Block

    • 全局类型block _NSConcreteGlobalBlock (堆)
    • 栈类型block _NSConcreteStackBlock (栈)
    • 堆类型block _NSConcreteMallocBlock (已初始化数据区)

    栈:拷贝 -》 堆:拷贝-》 堆(引用计数器+1)

    注意:
    使用了__block 修饰的的截获变量修改,会对block进行copy

    多线程

    大纲

    • GCD
    • NSOperation
    • NSThread
    • 多线程与锁

    GCD

    • 同步/异步 和 串行/并发
    • dispatch_barrier_aysnc
    • dispatch_group
    1. 同步/异步 和 串行/并发
      1.1 dispatch_sync(serial_queue /串行队列/,, ^{ // 任务 });
      1.2 dispatch_async(serial_queue, ^{ // 任务 });
      1.3 dispatch_sync(concurrent_queue /并发队列/, ^{ // 任务 });
      1.4 dispatch_async(concurrent_queue, ^{ // 任务 });

    2. dispatch_barrier_async
      2.1 如何实现多读单写
      dispatch_barrier_async(concurrent_queue, ^{ // 写操作 });

    3. dispatch_group
      3.1 A,B,C三个任务完成后,再执行D

    NSOperation

    1. NSOperationQueue
      1.1 可以添加任务依赖
      1.2 可以添加任务执行状态
      1.3 可以控制最大并发量

    任务执行状态

    • isReady
    • isExcuting
    • isFinished
    • isCancelled

    状态控制

    1. 只重写main时,则无法控制状态
    2. 重写了start,自行控制任务状态

    通过KVO来监听NSOperation状态

    NSThread

    • 如何实现常驻线程
    • Start方法内部实现机制(开启线程,执行函数,关闭线程)

    多线程和锁

    • NSRecursiveLock
    • NSLock
    • dispatch_semaphore_t
    @synchronized

    单例对象

    atomic

    原子性赋值

    OSSpinLock

    自旋锁(循环等待访问,不释放当前资源)

    NSLock
    NSRecursiveLock

    递归锁,可以重注

    dispatch_semaphore_t

    信号量

    RunLoop

    大纲

    • 概念
    • 数据结构
    • 事件循环机制
    • RunLoop与NSTimer
    • RunLoop与多线程

    什么是RunLoop

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

    • 维护事件循环
    • 处理事件和消息的
    • 对象
    1. 事件循环
    • 没有消息处理时,休眠以避免资源占用
    • 有消息需要处理时,立刻唤醒
    • main函数中,开启了运行循环,保证函数不会被结束,等待 ≠ 死循环

    数据结构

    • NSRunLoop => Foundation
    • CFRunLoop => CoreFoundation

    CFRunLoop:

    • name: 某一个runloopMode的名称,通过名称来找到模式
    • sources0: CFRunLoopSource => source0 手动唤醒
    • sources1: source1 具备唤醒线程的能力
    • observers: 观测时间点
    • timers:runloop的定时器

    1 RunLoop -> n Model:

    • m Source
    • m Timer
    • m Observer

    事件循环的实现机制

    1. 即将进入RunLoop
    2. 将要处理Timer/Source0事件
      通知Observer
    3. 处理Source0事件
    4. 如果有Source1要处理 -> 8. 处理唤醒时收到的消息
    5. 线程将要休眠
    6. 休眠、等待唤醒
      6.1 Source1
      6.2 Timer事件的回调
      6.3 外部手动唤醒
    7. 线程刚被唤醒
    8. 即将退出RunLoop

    RunLoop的核心

    RunLoop与NSTimer

    NSCommonMode

    RunLoop与多线程

    • 线程和RunLoop是一一对应的
    • 新建的线程默认是没有RunLoop的

    怎样实现一个常驻线程

    1. 创建一个RunLoop
    2. 添加port/source给RunLoop
    3. 启动RunLoop

    网络

    大纲

    HTTP协议
    HTTPS与网络安全
    TCP/UDP

    相关文章

      网友评论

          本文标题:2021-06-19

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