iOS UI视图面试相关

iOS UI视图面试相关

UITableVIew相关

  • 重用机制
cell = [tableView dequeueReusableCellWillIdentifier:identifer];
image-20250706155208317

其中A2、A3、A4、A5是完全显示在屏幕,A2、A6显示部分,A1和A7不在显示范围内,假如现在是从下滑时的结果,在A1消失时会被放入到重用池,在A7显示时从重用池里取一个cell来使用,如果cellA1-A7都是一个identifer,那么A7会拿到A1的cell来进行重用

复用池的实现:

#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
// 实现重用机制的类
@interface ViewReusePool : NSObject// 从重用池当中取出一个可重用的view
- (UIView *)dequeueReusableView;// 向重用池当中添加一个视图
- (void)addUsingView:(UIView *)view;// 重置方法,将当前使用中的视图移动到可重用队列当中
- (void)reset;@end
#import "ViewReusePool.h"@interface ViewReusePool ()
// 等待使用的队列
@property (nonatomic, strong) NSMutableSet *waitUsedQueue;
// 使用中的队列
@property (nonatomic, strong) NSMutableSet *usingQueue;
@end@implementation ViewReusePool- (id)init{self = [super init];if (self) {_waitUsedQueue = [NSMutableSet set];_usingQueue = [NSMutableSet set];}return self;
}- (UIView *)dequeueReusableView{UIView *view = [_waitUsedQueue anyObject];if (view == nil) {return nil;}else{// 进行队列移动[_waitUsedQueue removeObject:view];[_usingQueue addObject:view];return view;}
}- (void)addUsingView:(UIView *)view
{if (view == nil) {return;}// 添加视图到使用中的队列[_usingQueue addObject:view];
}- (void)reset{UIView *view = nil;while ((view = [_usingQueue anyObject])) {// 从使用中队列移除[_usingQueue removeObject:view];// 加入等待使用的队列[_waitUsedQueue addObject:view];}
}@end
  • 数据源同步
image-20250706163446910

删除一般是在主线程操作,删除时往往会触发后向刷新LoadMore,这就涉及到多线程对共享数据的访问,需要考虑数据源同步问题,解决方案:

  • 并发访问、数据拷贝
image-20250706163902920

在子线程请求数据时,主线程做了删除操作,导致数据不同步

主线程记录删除操作,在子线程中返回数据前同步删除操作

image-20250706164110828
  • 串行访问

子线程进行网络请求、数据解析,网络请求回来时在串行队列去进行新增数据预排版(子线程当中),在这期间主线程删除了某个数据,在串行队列当中前一个block完成之后去执行同步主线程发送过来的任务同步数据删除,然后再去回到主线程更新UI。

image-20250706164957876

事件传递 & 视图响应

UIVIew和CALayer的区别

  • UIView为其提供内容,以及负责处理触摸等事件,参与响应链
  • CALayer负责显示内容contents

UIView实际上是对CALayer的轻量级封装。每个UIView都有一个关联的CALayer作为其backing store,负责实际的渲染工作,而UIView则处理用户交互和事件响应。CALayer通过contents属性提供要显示的位图信息,UIView继承自UIResponder,而CALayer继承自NSObject,UIView主要负责处理用户交互,如触摸、点击和拖动等事件。而CALayer则专注于渲染和动画处理

事件传递与视图响应链

假如点击了c2的空白区域,系统最终怎么样找到响应视图为c2的?

image-20250706170637631
事件传递:寻找最佳响应者(Hit-Testing)
image-20250706171102674

事件传递是从父控件到子控件的正向传递过程点击屏幕 → UIApplication → UIWindow → 父视图 → 子视图),目标是找到最合适的视图(Hit-Test View)处理触摸事件。

  1. 核心方法

    • hitTest:withEvent::递归调用子视图的该方法,返回最终处理事件的视图。
    • pointInside:withEvent::判断触摸点是否在视图范围内,是hitTest的底层依赖方法
  2. 传递规则

    image-20250706171937365
    • UIWindow开始,遍历子视图(从后往前,即最上层的子视图优先)。
    • 若视图满足以下条件,则继续向其子视图传递:
      • userInteractionEnabled = YES
      • hidden = NO
      • alpha > 0.01
      • 触摸点在视图范围内(通过pointInside验证)。
    • 若当前视图无子视图或子视图不满足条件,则自身成为最佳响应者。
  3. 特性

    • 即使父视图是最佳响应者,仍会递归调用所有子视图的hitTest方法(确保无更合适的子视图)5。
    • 可重写hitTest:withEvent:实现特殊事件拦截(如扩大按钮点击区域)。
响应链:事件处理流程

当最佳响应者无法处理事件时,事件沿响应链反向传递(从子控件到父控件),直至被处理或丢弃。

  1. 响应链构成
    响应链由UIResponder对象(UIViewUIViewController等)通过nextResponder连接:

    最佳响应视图 → 父视图 → ... → 控制器 → UIWindow → UIApplication → AppDelegate
    
    • 视图的nextResponder:若视图是控制器的根视图,则指向控制器;否则指向父视图。
    • 控制器的nextResponder:指向其视图的父视图或UIWindow
  2. 事件响应逻辑

    • 最佳响应者优先处理事件(如实现touchesBegan:withEvent:)。
    • 若未处理,调用[super touchesBegan...]将事件传递给nextResponder
    • 若响应链中所有对象均未处理,事件被静默丢弃(不会崩溃)。

UI卡顿掉帧

image-20250713111644302

通常情况下,屏幕刷新率为60Hz,意味着每秒需要渲染60帧画面,即每帧的渲染时间不应超过16.7毫秒。如果某一帧的渲染时间超过了16.7毫秒,就会导致卡顿或掉帧现象,影响用户体验

绘制原理

image-20250713112834763

为什么调用[UIView setNeedsDisplay]并没有立即进行视图的绘制工作?

在当前Runloop将要结束才会介入UI视图的绘制流程当中

异步绘制

  • 异步绘制:通过实现 CALayer 的代理方法 displayLayer,在子线程中生成位图,减少主线程的负担。
image-20250713114045209

离屏渲染

在屏渲染:也为当前屏幕渲染,GPU的渲染操作是在当前用于显示的屏幕缓冲区中进行

离屏渲染:GPU在当前屏幕缓冲区以外新开辟一个缓冲区进行渲染操作

避免离屏渲染:尽量避免使用 layer 的圆角、边框、阴影等属性,这些属性会触发离屏渲染,增加 GPU 的负担,可能导致GPU和CPU的总耗时超过16.7ms,可能会掉帧,可以在后台线程预先绘制好对应内容,减少 GPU 的工作量。

常见的触发离屏渲染的属性

  1. 圆角 (cornerRadius)
    • 当设置 layer.cornerRadius 属性并且 masksToBoundsYES 时,会触发离屏渲染。这是因为 masksToBounds 会应用到所有的图层上,需要在离屏缓冲区中进行圆角裁剪处理。
    • 如果 layer 只有一个图层且没有 content,设置 cornerRadiusmasksToBounds 不会触发离屏渲染。
  2. 阴影 (shadow\*)
    • 当设置 layer.shadow* 属性时,如果阴影路径(shadowPath)没有设置,系统需要离屏渲染来计算阴影。阴影需要在所有内容绘制完成后根据外轮廓进行绘制,因此需要在离屏缓冲区中进行处理。
  3. 图层蒙版 (mask)
    • 使用 layer.mask 或者 layer.masksToBounds 时会触发离屏渲染。这是因为蒙版需要在离屏缓冲区中进行剪裁处理。
  4. 组透明度 (group opacity)
    • 设置 layer.allowsGroupOpacity 或者 layer.opacity 时,如果 opacity 小于1,会触发离屏渲染。这是因为透明度需要在离屏缓冲区中进行混合处理。
  5. 光栅化 (shouldRasterize)
    • 开启 layer.shouldRasterize 会触发离屏渲染。光栅化会将 layer 的渲染结果保存在离屏缓冲区中,以便在后续帧中复用,减少重复渲染的开销

滑动优化方案

基于tableview、scrollview的滑动优化方案

  • CPU方面

可以在子线程进行一些对象创建、调整、销毁、包括进行预排版(布局计算、文本计算)、预渲染(文本等异步绘制、图片编解码等)

  • GPU方面

避免离屏渲染,尽量避免使用 layer 的圆角、边框、阴影等属性,这些属性会触发离屏渲染,增加 GPU 的负担

异步绘制:通过实现 CALayer 的代理方法 displayLayer,在子线程中生成位图,减少主线程的负担。例如,微博的头像在下载后会在后台线程预先渲染为圆形并保存到缓存中,这样可以减少主线程的渲染压力。

复用机制:不要一次性创建所有子视图,而是在需要时创建,并复用它们。这样可以减少内存分配的开销,节省内存空间。UITableView 和 UICollectionView 的复用机制就是一个很好的例子。

懒加载:把创建对象的时机延后到不得不需要它们的时候,减少初始加载时间。

按需加载:在滑动过程中,按需加载对应的内容。例如,当目标行与当前行相差超过指定行数时,只在目标滚动范围的前后指定几行加载,减少不必要的加载操作。

自动加载更新数据:在滚动到特定位置时,自动加载更多数据,减少用户等待时间。

面试问题总结:

  1. 系统的UI事件传递机制是怎样的?
  2. 使UITableView滚动更流畅的方案或思路都有哪些?
  3. 什么是离屏渲染?
  4. UIView和CALayer之间的关系是怎样的?

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/news/914616.shtml
繁体地址,请注明出处:http://hk.pswp.cn/news/914616.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

网络编程-tcp连接:服务器与客户端

使用服务器和客户端的代码&#xff0c;实现服务器和客户端的互相聊天功能 实现两台电脑之间互相聊天 方案一&#xff1a;服务器代码&#xff08;server.c&#xff09;#include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h>…

跨平台移动开发技术深度分析:uni-app、React Native与Flutter的迁移成本、性能、场景与前景

1. 引言 跨平台移动开发技术已成为提升开发效率、降低成本的战略性选择。uni-app、React Native&#xff08;RN&#xff09;和Flutter作为主流方案&#xff0c;在迁移成本、应用性能、适用场景及未来发展上呈现显著差异。本报告基于最新行业数据与技术演进&#xff08;2025年&…

详解低速容错CAN(附与高速CAN对比表)

文章目录前言一、低速容错CAN-低速二、低速容错CAN-容错2.1 信号电平2.2 终端电阻2.3 容错机制前言 在ISO 11898-3 Low-speed, fault-tolerant, medium-dependent interface部分描述了低速CAN的容错行为及其物理层内容。既然称为低速容错CAN&#xff0c;主要需要搞清楚的两个核…

维基框架发布 1.0.11 至中央仓,深化国产化 DevOps 生态整合

一、核心事件&#xff1a;维基框架 1.0.11 正式入驻中央仓库​ ​维基框架&#xff08;Wiki-Framework&#xff09;​​ 作为国产全场景 Java 企业级开发框架&#xff0c;于 7 月 9 日正式发布 ​v1.0.11 版本​ 至中央软件仓库&#xff08;Maven Central&#xff09;&#xf…

vscode 打开c++文件注释乱码

之前一直都主要用vscode编辑lua和python脚本语言&#xff0c;没怎么编辑过c文件&#xff0c;今天想打开一个文件看一个东西&#xff0c;但是注释全部乱码了&#xff0c;我也知道是文件编码的问题&#xff0c;但没找到修改编码格式的地方&#xff0c;好了废话不多说&#xff0c;…

波动回升正当时!期权合成多头:震荡市攻守兼备利器

上周&#xff0c;A股喜提关键突破&#xff01;上证指数自21年初以来首次稳稳站上3500点大关&#xff0c;市场整体震荡上行。尐程序&#xff1a;期权汇不过&#xff0c;热闹之下也藏有隐忧&#xff1a;虽然日均成交维持在1.4万亿加&#xff0c;但周五放量冲高&#xff08;成交达…

Python 基础(十四): 错误和异常

目录 1 错误2 异常 2.1 内置异常2.2 异常处理2.3 抛出异常2.4 自定义异常 程序中的错误我们通常称为 bug &#xff0c;工作中我们不仅需要改自己程序中的 bug &#xff0c;还需要改别人程序中的 bug &#xff0c;新项目有 bug 要改&#xff0c;老项目也有 bug 要改&#xff…

OpenCV-Python Tutorial : A Candy from Official Main Page(三)

3.11傅立叶变换3.11.1Fourier Transform in OpenCV-cv.dft、cv.magnitude、cv.idft这两个函数是图像频域处理&#xff08;如去噪、边缘增强、纹理分析&#xff09;的基础工具。1.cv.dft() —— 离散傅里叶变换功能&#xff1a; 将图像从空间域&#xff08;像素强度&#xff09;…

移动端字体适配

一、移动端图片适配1、使用 <img> 的 srcset<img src"logo.png"srcset"logo2x.png 2x,logo3x.png 3x"alt"Logo">优点&#xff1a;原生支持&#xff0c;浏览器自动选择最合适的图片。2、使用媒体查询切换背景图.logo {background-ima…

git起步

git官网&#xff1a;https://git-scm.com git使用手册&#xff1a;https://git-scm.com/book/zh/v2 一、Git 是什么&#xff1f; 1、版本控制 版本控制是一种记录一个或若干文件内容变化&#xff0c;以便将来查阅特定版本修订情况的系统。我们经常是用的是保存软件源代码的…

SSL与HTTP概述

一、概念1.SSL概念SSL&#xff08;Secure Sockets Layer&#xff09;是一种网络安全协议&#xff0c;用于在互联网通信中建立加密链接&#xff0c;保护在网络中传输的敏感数据免遭窃取或篡改。2.TLS概念虽然现在更先进的 TLS&#xff08;Transport Layer Security&#xff09; …

前端报错:“Uncaught SyntaxError: missing ) after argument list

问题描述&#xff1a;前端报错&#xff1a;“Uncaught SyntaxError: missing ) after argument list在 JavaScript 中遇到“SyntaxError: missing ) after argument list”这个错误通常意味着在函数调用或者声明中&#xff0c;参数列表的括号没有正确闭合。错误代码&#xff1a…

广州邮科光纤交换机的应用:网络世界中的幕后核心

你知道吗&#xff1f;在我们每天畅游互联网&#xff0c;发送邮件、看视频、打游戏时&#xff0c;背后支撑这一切流畅体验的关键设备之一就是光纤交换机。它像一个幕后英雄&#xff0c;默默地确保信息传输高效、稳定。那么&#xff0c;究竟邮科光纤交换机有哪些不可或缺的应用领…

C++内存布局、构造函数规则和优化策略解析

一、类对象内存布局深度解析 1.1 核心内存占用规则 ​非静态成员变量​&#xff1a;每个对象独立存储&#xff0c;按声明顺序排列&#xff08;含内存对齐填充&#xff09; 示例&#xff1a;class A{int x; char y;}; → 实际占用8字节&#xff08;413填充&#xff09;4​静态…

Fastapi框架总览与核心架构

Fastapi框架总览与核心架构 FastAPI 是一个基于 Python 的现代 Web 框架&#xff0c;专注于 高性能、高并发 和 开发效率&#xff0c;特别适合构建 异步 API 服务、微服务接口&#xff0c;同时在大模型接口封装中也广泛应用。它基于 Starlette&#xff08;异步 Web 框架&#x…

高并发四种IO模型的底层原理

高并发四种IO模型的底层原理 1 IO读写的基本原理 为了避免用户进程直接操作内核&#xff0c;保证内核安全&#xff0c;操作系统将内存&#xff08;虚拟内存&#xff09;划分为两部分&#xff1a;一部分是内核空间(Kernel-Space)&#xff0c;另一部分是用户空间(User-Space)。在…

腾讯云短信实战:Spring Boot接入YML配置与签名/模板/发送/统计/状态/号码包工具类详解

下面是一个Spring Boot集成腾讯云短信服务的详细示例&#xff0c;包含配置和6个工具类&#xff08;签名、模板、发送、统计、状态&#xff09;&#xff0c;采用YML配置&#xff1a; 1. 添加Maven依赖 <dependency><groupId>com.tencentcloudapi</groupId>&…

【Java篇】IntelliJ IDEA 安装与基础配置指南

序 本篇文章将介绍IDEA 2023 版本。 提高开发人员的生产力。无论您是刚开始接触编程的新手&#xff0c;还是经验丰富的开发专家。 一&#xff1a;官网下载安装包&#xff1a; IDEA下载链接 这个版本可以根据自己的需要选择。 二、安装方法 双击进这个.exe文件 这里要选择合…

2-Nodejs运行JS代码

2-Nodejs运行JS代码 创建一个 js 文件编写 JS 代码 要注意的是&#xff0c;在nodejs环境中不能操作浏览器 DOM 对象相关的api&#xff0c;在Nodejs 中运行 JS 代码 按住 shift 键&#xff0c;在 js 文件所在文件夹空白处右键&#xff0c;选择 Powershell 窗口执行如下命令&…

vue中使用西瓜播放器xgplayer (封装)+xgplayer-hls 播放.m3u8格式视频

1.西瓜播放器官网 http://h5player.bytedance.com/guide/2.安装 # 最新稳定版 $ npm install xgplayer对于已有项目也可以通过 CDN 引入&#xff0c;代码如下&#xff1a; <script src"//unpkg.byted-static.com/xgplayer/2.31.2/browser/index.js" type"tex…