美文网首页
iOS知识点总结

iOS知识点总结

作者: 烟影很美 | 来源:发表于2023-04-12 10:33 被阅读0次

    多线程:

    进程和线程的区别:进程是火车, 线程是车厢。进程间不共享上下文, 同一进程下的线程共享进程的上下文
    • 同步(sync):阻塞当前线程, 任务立即执行
    • 异步(async):可以在新的线程中执行任务, 具备开启新线程的能力。
    • 串行:同一时间只有一个任务执行
    • 并行:同一时间有多个任务执行(多核)
    • 并发:单核通过时间片轮转宏观上实现并行的机制


    数据结构:

    • 堆:逻辑结构完全二叉树, 可以用一维数组实现, 这种数据结构方便求极值。向上调整算法/向下调整算法
    • 栈:先进后出, 可以用一维数组或者链表实现

    内存:

    • 堆:动态分配, 主要为了解决栈空间释放后变量也被释放的问题
    • 栈:逻辑上先进后出, 由系统控制。


    Swift:

    函数调用方式:

    静态, 动态。动态包括函数表调用和消息发送。扩展(extension)没有函数表, 所以只能使用静态或者消息发送的方式。结构体及其扩展静态调用;类默认函数表调用, final-静态, @objc-函数表, dynamic-消息发送;类扩展默认使用静态调用, 类扩展+@objc/dynamic-消息发送

    Swift与OC区别:
    1. Swift是静态语言, 有类型推断, OC是动态语言
    2. Swift面向协议编程, OC面向对象编程
    3. Swift注重值类型, OC注重引用类型
    4. Swift支持泛型, OC只支持轻量泛型
    5. Swift支持静态派发(效率高)、动态派发(函数表派发、消息派发), OC支持动态派发(消息派发)
    6. Swift支持函数式编程
    7. Swift的协议不仅可以被类实现, 也可以被structenum实现
    8. Swift有元组类型、支持运算法重载
    9. Swift支持命名空间
    10. Swift支持默认参数(函数)
    11. Swift比OC代码更简洁
    12. 值类型优化:如写时拷贝

    Block:

    全局block在数据区, 没有捕获变量的block原本应该在栈, 但是编译器优化, 转移到了数据区。捕获变量的block变量会在堆, 但如果是block对象, 因为没有变量名, 所以不会再其他地方调用, 会在栈。捕获变量的block对象如果对其使用copy, 会在堆。(MRC下, 如果不对捕获变量的block使用COPY, 就在栈)


    layoutSubviews调用时机:

    有尺寸且添加到父View上时, 父视图是ScrollView且滚动时, 改变尺寸时


    load、initialize方法的区别:

    • 调用方式

    1. load是根据函数地址直接调用
    2. initialize是通过objc_msgSend调用

    • 调用时刻

    1. load是runtime加载类、分类的时候调用(只会调用1次)
    2. initialize是类第一次接收到消息的时候调用, 每一个类只会initialize一次,

    如果有SubClass继承Class.
    则在SubClass第一次收到消息时, 会先调用SubClass-initialize, 再调用Class-initialize;
    如果SubClass没有重写initialize, 则在SubClass-initialize过程中触发Class-initialize, 表现为Class-initialize被调用了两次. 即一个类向上的继承树上有N个类, 在接收到消息时就会触发N+1initialize, 如果某个类没有重写initialize, 则会向上调用最近的initialize
    综上: 重写initialize时需用考虑使用dispatchonce避免重复调用和初始化.


    热启动与冷启动

    参考: http://events.jianshu.io/p/783d8b3ef884https://www.jianshu.com/p/4c1adabc8b90

    1. 热启动:就是按下home键的时候, app还存在一段时间, 这时点击app马上就能恢复到原状态, 这种启动我们称为热启动。当APP 启动时需要的 dylibs 仍然停留在设备的磁盘缓存的时候,这个时候就是热启动,热启动的速度会更快。
    2. 冷启动:app被kill掉之后, 重新打开启动过程为冷启动。

    性能优化:


    冷启动:

    冷启动可大致分为两个阶段, 分别为main函数之前、main之后到didFinishLaunching执行完毕, 很多时候, 首页的完成展示前的阶段可包含在启动阶段内. 上述两个阶段为pre-mainmain.

    pre-main阶段:
    pre-main的过程
    1. 加载mach-o可执行文件
    2. 加载dyld到App进程,
    3. 加载动态库(包括所依赖的所有动态库)
    4. Rebase 内部指针调整。
    5. Bind 把指针正确的指向Image外部的内容。通过符号表查找
    6. 初始化Objective-C Runtime, Objc运行时的初始化处理, 包括Objc相关类的注册、category注册、selector唯一性检查
    7. 其他初始化, 包括执行了+load()方法、attribute((constructor))修饰的函数调用、创建C++静态全局变量
    针对pre-main的优化:
    1. 尽量缩小mach-o的大小(待研究) - 1
    2. 减少动态库, 在动态库较多时将多个动态库合并 - 3
    3. 减少Objc类, category的数量, 清除用不到的类、函数 - 4, 6
    4. 使用dispatchonce+initialize代替+load, 尽量减少attribute((constructor))的调用, 也可以考虑用dispatchonce+initialize代替 - 7
    5. 二进制重排.
    t1.png
    main阶段:
    1. dyld调 main()
    2. 调UIApplicationMain()
    3. 调applicationWillFinishLaunching
    4. 调didFinishLaunchingWithOptions

    这部分包含大量APP配置和业务代码, 梳理好其内容, 将能延后的内容尽量延后, 此阶段可用的办法有:

    1. 延后部分代码执行
    2. 使用闪屏优化体验
    3. 内嵌启动首页展示数据
    4. 多线程

    热启动

    1. 数据优化,将耗时操作做异步处理。
    2. 检查NSUserDefaults的存储,NSUserDefaults实际上是在Library文件夹下会生产一个plist文件,加载的时候是整个plist配置文件全部load到内存中。所以非常频繁的存取大量数据也是有可能导致APP启动卡顿的

    卡顿

    参考 https://zhuanlan.zhihu.com/p/502990984

    手机成像过程

    产生卡顿是由于屏幕的成像显示导致, 而屏幕画面的显示离不开手机的CPU和GPU. CPU主要负责计算, 比如说界面的布局排版, 文字的大小和颜色, 图片显示的解码等操作都需要CPU计算, CPU将计算好的数据提交给GPU, GPU就将CPU计算好的数据进行渲染。因为屏幕显示的数据是特定格式的,只有通过GPU渲染过的数据才能显示在屏幕上;GPU把渲染过的数据放到帧缓存区, 视频控制器从帧缓存区读取数据显示到屏幕上.


    卡顿.png
    卡顿的主要原因

    CPU和GPU所花费的时间太长从而造成俗称的丢帧(掉帧). 垂直同步信号的发射频率是固定的, 信号发出, 表明着即将显示数据。若是期间, CPU或GPU有一步耗时较长(第3帧的渲染), 垂直信号已发出, 可是GPU尚未渲染完, 那么就是显示渲染好的第2帧数据, 连续显示相同的帧, 就形成了画面卡顿; 第3帧会在第4次同步信号过来时再显示。这就是卡顿的根本原因.

    1. CPU和GPU

    CUP(Central processing Unit,中央处理器)
    对象的创建和销毁、对象属性的调整、布局计算、文本的计算和排版、图片的格式转换和解码、图像的绘制(Core Graphics)

    GPU (Graphics Processing Unit,图形处理器)
    纹理的渲染

    优化:
    • 尽可能减少CPU、GPU资源消耗
    • 尽量用轻量级的对象,比如用不到事件处理的地方,可以考虑使用CALayer取代UIView
    • 不要频繁地调用UIView的相关属性,比如frame、bounds、transform等属性,尽量减少不必要的修改
    • 尽量提前计算好布局,在有需要时一次性调整对应的属性,不要多次修改属性
    • Autolayout会比直接设置frame消耗更多的CPU资源
    • 图片的size最好刚好跟UIImageView的size保持一致
    • 控制一下线程的最大并发数量
    • 尽量避免短时间内大量图片的显示,尽可能将多张图片合成一张进行显示
    • GPU能处理的最大纹理尺寸是4096x4096,一旦超过这个尺寸,就会占用CPU资源进行处理,所以纹理尽量不要超过这个尺寸
    • 尽量减少视图数量和层次
    • 减少透明的视图(alpha<1),不透明的就设置opaque为YES
    • 尽量把耗时的操作放到子线程(文本尺寸、图片处理)
    2. 离屏渲染(尽量避免出现离屏渲染)

    在OpenGL中,GPU有2种渲染方式
    On-Screen Rendering:当前屏幕渲染,在当前用于显示的屏幕缓冲区进行渲染操作
    Off-Screen Rendering:离屏渲染,在当前屏幕缓冲区以外新开辟一个缓冲区进行渲染操作

    离屏渲染消耗性能的原因

    1、需要创建新的缓冲区
    2、离屏渲染的整个过程,需要多次切换上下文环境,先是从当前屏幕(On-Screen)切换到离屏(Off-Screen);等到离屏渲染结束以后,将离屏缓冲区的渲染结果显示到屏幕上,又需要将上下文环境从离屏切换到当前屏幕

    哪些操作会触发离屏渲染?

    光栅化,layer.shouldRasterize = YES
    遮罩,layer.mask
    ? 圆角,同时设置layer.masksToBounds = YES、layer.cornerRadius大于0(考虑通过CoreGraphics绘制裁剪圆角,或者叫UI提供圆角图片)
    阴影,layer.shadowXXX (如果设置了layer.shadowPath就不会产生离屏渲染)。


    耗电

    1. 尽可能降低CPU、GPU功耗
    2. 少用定时器
    3. 优化I/O操作
    4. 尽量不要频繁写入小数据,最好批量一次性写入
    5. 读写大量重要数据时,考虑用dispatch_io,其提供了基于GCD的异步操作文件I/O的API。用dispatch_io系统会优化磁盘访问
    6. 数据量比较大的,建议使用数据库(比如SQLite、CoreData)

    网络

    1. 减少、压缩网络数据
    2. 如果多次请求的结果是相同的,尽量使用缓存
    3. 使用断点续传,否则网络不稳定时可能多次传输相同的内容
    4. 网络不可用时,不要尝试执行网络请求
    5. 让用户可以取消长时间运行或者速度很慢的网络操作,设置合适的超时时间
    6. 批量传输,比如,下载视频流时,不要传输很小的数据包,直接下载整个文件或者一大块一大块地下载。如果下载广告,一 次性多下载一些,然后再慢慢展示。如果下载电子邮件,一次下载多封,不要一封一封地下载

    定位

    1. 如果只是需要快速确定用户位置,最好用CLLocationManager的requestLocation方法。定位完成后,会自动让定位硬件断电
    2. 如果不是导航应用,尽量不要实时更新位置,定位完毕就关掉定位服务
    3. 尽量降低定位精度,比如尽量不要使用精度最高的kCLLocationAccuracyBest
    4. 需要后台定位时,尽量设置pausesLocationUpdatesAutomatically为YES,如果用户不太可能移动的时候系统会自动暂停位置更新
    5. 尽量不要使用startMonitoringSignificantLocationChanges,优先考虑startMonitoringForRegion:
    6. 用户移动、摇晃、倾斜设备时,会产生动作(motion)事件,这些事件由加速度计、陀螺仪、磁力计等硬件检测。在不需要检测的场合,应该及时关闭这些硬件

    相关文章

      网友评论

          本文标题:iOS知识点总结

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