- 面向对象
- 视图
- 触发离屏渲染的场景:
- KVO & KVC
- Category分类
- Block代码块
- block的原理是怎样的?本质是什么?
- block类型?
- 请问__block的作用是什么?有什么使用注意点?
- block的属性修饰词为什么是copy?使用block有哪些使用注意?
- block在修改NSMutableArray,需不需要添加__block?
- 使用block时什么情况会发生引用循环,如何解决?">使用block时什么情况会发生引用循环,如何解决?
- 在block内如何修改block外部变量?">在block内如何修改block外部变量?
- 使用系统的某些block api(如UIView的block版本写动画时),是否也考虑引用循环问题?">使用系统的某些block api(如UIView的block版本写动画时),是否也考虑引用循环问题?
- iOS block 的原理,block 的属性修饰词为什么用 copy,使用 block 时有哪些要注意的?">iOS block 的原理,block 的属性修饰词为什么用 copy,使用 block 时有哪些要注意的?
- 消息机制
- Runtime相关
- RunLoop相关
- 讲讲RunLoop, 项目中有用到吗?
- 讲讲Runloop常见的使用场景?
- RunLoop内部实现逻辑?
- RunLoop和线程的关系?
- timer与RunLoop的关系?
- 程序中添加每3秒响应一次的NSTimer, 当拖动tableview时timer可能无法响应要怎么解决?
- RunLoop是怎么相应用户操作的,具体流程是什么样的?
- 说说RunLoop的几种状态
- RunLoop的mode作用是什么?
- 28. runloop和线程有什么关系?">28. runloop和线程有什么关系?
- 29. runloop的mode作用是什么?">29. runloop的mode作用是什么?
- 30. 以+ scheduledTimerWithTimeInterval…的方式触发的timer,在滑动页面上的列表时,timer会暂定回调,为什么?如何解决?">30. 以+ scheduledTimerWithTimeInterval…的方式触发的timer,在滑动页面上的列表时,timer会暂定回调,为什么?如何解决?
- 31. 猜想runloop内部是如何实现的?">31. 猜想runloop内部是如何实现的?
- 定时器(Timer)
- PerformSelector
- GCD
- 事件响应
- 手势识别
- 界面刷新
- 网络请求
- AutoreleasePool
- runloop与线程的关系
- 事件循环机制
- Runloop与NSTimer的关系
- Mode、Source、Timer、Observer
- 常驻线程的实现
- 多线程相关
- 进程和线程的区别?同步异步的区别?并行和并发的区别?">进程和线程的区别?同步异步的区别?并行和并发的区别?
- 何为线程安全?iOS中的各种锁性能与使用时机
- 40. GCD的队列(dispatch_queue_t)分哪两种类型?">40. GCD的队列(dispatch_queue_t)分哪两种类型?
- 41. 如何用GCD同步若干个异步调用?(如根据若干个url异步加载多张图片,然后在都下载完成后合成一张整图)">41. 如何用GCD同步若干个异步调用?(如根据若干个url异步加载多张图片,然后在都下载完成后合成一张整图)
- 42. dispatch_barrier_async的作用是什么?">42. dispatch_barrier_async的作用是什么?
- 43. 苹果为什么要废弃dispatch_get_current_queue?">43. 苹果为什么要废弃dispatch_get_current_queue?
- iOS 如果让你实现 GCD 的线程池,讲一下思路?">iOS 如果让你实现 GCD 的线程池,讲一下思路?
- 简述dispatch_once底层原理
- 谈下Objective C都有哪些锁机制,你一般用哪个?">谈下Objective C都有哪些锁机制,你一般用哪个?
- iOS下如何实现指定线程数目的线程池?">iOS下如何实现指定线程数目的线程池?
- 多线程有哪几种?你更倾向于哪一种?">多线程有哪几种?你更倾向于哪一种?
- dispatch_barrier_async 的作用是什么?">dispatch_barrier_async 的作用是什么?
- 你理解的多线程是?
- 请简单说明多线程技术的优点和缺点?
- 请简单说明线程和进程,以及他们之间的关系?
- IOS多线程方案有哪几种?你更倾向于哪一种?
- 请简单说明主线程的作用,以及使用注意点?
- 请简单列出NSThread线程的几种状态,并说明状态转换的逻辑?
- 请简单说明如何简单的解决多线程访问同一块资源造成的线程安全的问题,以及注意点?
- GCD和NSOperation的对比?
- NSOperation和NSOperationQueue的好处有?
- 线程安全,线程同步方案?
- 自旋锁与互斥锁的比较?
- atomic和nonatomic的区别?
- 多线程文件读写安全,多读单写?
- 使用CADispaly、NSTimer有什么注意点?
- 请问下面题的打印结果是?
">
- 内存管理相关
- iOS 中内省的几个方法?">iOS 中内省的几个方法?
- 介绍下内存的几大区域?
- 什么是TaggedPointer?
- 讲一下你对IOS内存管理的理解?
- ARC都帮我们做了什么?
- 方法里有局部对象,出了方法后会立即释放吗?
- Copy和MutableCopy的区别?
- copy和strong区别的区别?
- weak指针的实现原理是?
- 什么情况使用 weak 关键字?,weak和assign的区别?
- 如何让自己的类用 copy 修饰符?如何重写带 copy 关键字的 setter?
- 用@property声明的NSString(或NSArray,NSDictionary)经常使用copy关键字,为什么?如果改用strong关键字,可能造成什么问题?@
- synthesize合成实例变量的规则是什么?假如property名为foo,存在一个名为_foo的实例变量,那么还会自动合成新变量么?
- 在有了自动合成属性实例变量之后,@synthesize还有哪些使用场景?
- objc使用什么机制管理对象内存?">objc使用什么机制管理对象内存?
- ARC通过什么方式帮助开发者管理内存?">ARC通过什么方式帮助开发者管理内存?
- APP启动时,代码是怎么加载的,内存分了哪些区?
- 简述iOS内存管理机制
- 内存分区
- 循环引用
- 引用计数
- 自动释放池
- 弱引用表
- 堆和栈的区别?
- property属性修饰
- autoreleasepool自动释放池
- xcode工具
- 性能优化
- 调试
- 网络
- 算法
- 七种常见的数组排序算法整理(C语言版本)">七种常见的数组排序算法整理(C语言版本)
- 2019 算法面试相关(leetcode)—数组和链表
2019 算法面试相关(leetcode)—字符串
">2019 算法面试相关(leetcode)—数组和链表
2019 算法面试相关(leetcode)—字符串 - 2019 算法面试相关(leetcode)—栈和队列
">2019 算法面试相关(leetcode)—栈和队列 - 2019 算法面试相关(leetcode)—优先队列
">2019 算法面试相关(leetcode)—优先队列 - 2019 算法面试相关(leetcode)—哈希表
">2019 算法面试相关(leetcode)—哈希表 - 2019 算法面试相关(leetcode)—树、二叉树、二叉搜索树
">2019 算法面试相关(leetcode)—树、二叉树、二叉搜索树 - 2019 算法面试相关(leetcode)—递归与分治
">2019 算法面试相关(leetcode)—递归与分治 - 2019 算法面试相关(leetcode)—贪心算法
">2019 算法面试相关(leetcode)—贪心算法 - 2019 算法面试相关(leetcode)—动态规划(Dynamic Programming)
">2019 算法面试相关(leetcode)—动态规划(Dynamic Programming) - 2019 算法面试相关(leetcode)—动态规划之背包问题">2019 算法面试相关(leetcode)—动态规划之背包问题
- 哈希原理">哈希原理
- 哈希存储过程">哈希存储过程
- 静态库与动态库
- Mach-O与符号
- 架构与设计模式
面向对象
OC对象的本质是什么?
OC代码的底层实现其实都是C/C++代码,编译器先把OC代码转换成C/C++代码,接着转成汇编语言,最后转成机器语言最终运行在手机上; 所以OC代码的本质其实就是c/c++代码;Objective-C的面向对象都是基于C/C++的数据结构实现的。
一个NSObject对象占用多少内存?
一个NSObject对象,转为C/C++代码时,会包含一个isa指针,一个指针占用8个字节,但苹果的内存对齐是16个字节,因为,系统分配了16个字节,实际使用了8个字节。
sizeof是什么?
sizeof是C/C++中的一个操作符(operator)并不是一个函数,其作用返回一个对象或者类型所占的内存字节数。
对象的isa指针指向哪里?
instance对象
的isa
指针指向class
。当调用对象方法时,通过instance
的isa
找到class
,最后找到对象方法的实现进行调用class对象
的isa
指向meta-class。当调用类方法时,通过class
的isa
找到meta-class
,最后找到类方法的实现进行调用。类对象的superClass
指针,当有继承的时候,调用用父类的对象方法或者类方法时。通过isa
指针找到class
,然后通过superclass
找到继承类的class
,找到对象方法调用meta-class对象
的isa
指针指向基类的meta-class
对象
对象的superclass指针指向哪里?
instance对象
的isa指针
指向class类对象
,instance对象
的superClass指针
指向父类class对象
。
OC类信息存放在哪里?
- 对象方法,属性,成员变量,协议信息存放在
class对象
中- 类方法存放在
meta-class对象
中- 成员变量的具体值存放在
instance对象
中
一个objc对象如何进行内存布局?(考虑有父类的情况)
- 所有父类的成员变量和自己的成员变量都会存放在该对象所对应的存储空间中.
- 每一个对象内部都有一个isa指针,指向他的类对象,类对象中存放着本对象的
- 对象方法列表(对象能够接收的消息列表,保存在它所对应的类对象中)
- 成员变量的列表
- 属性列表
- 类对象内部也有一个isa指针指向元对象(meta class),元对象内部存放的是类方法列表,类对象内部还有一个superclass的指针,指向他的父类对象
一个objc对象的isa的指针指向什么?有什么作用?
对象的isa指向类,类的isa指向元类(meta class),元类isa指向元类的根类。 isa指针指向他的
类对象
,从而可以找到对象上的方法
视图
iOS UIViewController的完整生命周期?
-[ViewController initWithNibName:bundle:];
-[ViewController init];
-[ViewController loadView]; // loadView在controller的view为nil时调用
-[ViewController viewDidLoad];
-[ViewController viewWillAppear:];
-[ViewController viewDidAppear:];
-[ViewController viewWillDisappear:];
-[ViewController viewDidDisappear:];
iOS frame和bounds有什么不同?
frame
的位置是以父视图的坐标系为参照,对于视图或者图层来说,frame
并不是一个非常清晰的属性,它其实是一个虚拟属性,是根据bounds
,position
和transform
计算而来,所以当其中任何一个值发生改变,frame都会变化。bounds
是一个CGRect
结构,描述视图自己的坐标系以及视图大小;
iOS view的touch事件有哪些?
- UITouch
- 当用户用一根手指触摸屏幕时,会创建一个与手指相关联的UITouch对象 一根手指对应一个UITouch对象
- 根据touches中UITouch的个数可以判断出是单点触摸还是多点触摸。
- 保存着跟手指相关的信息,比如触摸的位置、时间、阶段
- 当手指移动时,系统会更新同一个UITouch对象,使之能够一直保存该手指在的触摸位置
- 当手指离开屏幕时,系统会销毁相应的UITouch对象
- UIEvent
- 每产生一个事件,就会产生一个UIEvent对象。
- UIEvent:称为事件对象,记录事件产生的时刻和类型。
- UIEvent还提供了相应的方法可以获得在某个view上面的触摸对象(UITouch)。
iOS 中的响应者链的工作原理?
当有touch事件来的时候,会从最下面的视图开始执行 hitTest:withEvent: ,如果符合成为响应者的条件,就会继续遍历它的 subviews 继续执行 hitTest:withEvent: ,直到找到最合适的view成为响应者。 注意,响应需要符合以下前提条件:
- touch事件的位置在响应者区域内
- 响应者 hidden 属性不为 YES
- 响应者 透明度 不是 0
- 响应者 userInteractionEnabled 不为 NO
iOS-使用hitTest控制点击事件的响应对象
- 1、首先在当前视图的hitTest方法中调用pointInside方法判断触摸点是否在当前视图内
- 2、若pointInside方法返回NO,说明触摸点不在当前视图内,则当前视图的hitTest返回nil,该视图不处理该事件
- 3、若pointInside方法返回YES,说明触摸点在当前视图内,则从最上层的子视图开始,遍历当前视图的所有子视图,调用子视图的hitTest方法重复步骤1-3
- 4、直到有子视图的hitTest方法返回非空对象或者全部子视图遍历完毕
- 5、若第一次有子视图的hitTest方法返回非空对象,则当前视图的hitTest方法就返回此对象,处理结束
- 6、若所有子视图的hitTest方法都返回nil,则当前视图的hitTest方法返回当前视图本身,最终由该对象处理触摸事件
iOS 列表卡顿的原因可能有哪些?你平时是怎么优化的?
按照60FPS的刷帧率,每隔16ms就会有一次VSync信号,卡顿是因为cpu和gpu由于执行的任务操作比较繁重,不能在视频同步信号到达前合成显示内容到 视频缓冲区中,导致无数据显示,所以界面还是显示之前的内容,假如1秒内的总视频帧过少,就导致肉眼看起来明显的卡顿;因此,优化的话,可以尽可能往减少CPU、GPU资源消耗方面入手。
- 利用cell视图重用技术,减少视图的构建
- 尽量提前计算好布局,缓存高度等等,避免操作过程中频繁计算。
- Autolayout会比直接设置frame消耗更多的CPU资源
- 图片的size最好刚好跟UIImageView的size保持一致,图片处理(解码、绘制)时,尽量避免短时间内大量图片的显示
- 尽量把耗时的操作放到子线程(控制一下线程的最大并发数量)
- 尽量避免出现离屏渲染
iOS屏幕撕裂的原因以及解决方案是什么?
在最初的时候, 帧缓冲区只有一个, 这种情况下帧缓冲区的
读取 和 刷新
都会有比较大的效率问题。为了解决效率问题, 显示系统后来引入两个缓冲区, 也就是 双缓冲机制 。
- 这种情况下, GPU 会首先渲染好一阵放入到一个缓冲区内让视频控制器去读取, 当下一帧渲染好之后, GPU 会直接把 视频控制器 的指针指向 第二个缓冲区。这样一来效率得到了很大的提升。
撕裂现象
- 双缓冲区解决了之前单缓冲区的效率问题, 但是又引入了一个新的问题。当视频控制器还没有读取完成时, 也就是屏幕内容还没有显示完成 1 帧画面时, GPU 又将新的一帧内容提交到 帧缓冲区 并且把两个缓冲区进行交换。这时候视频控制器就会把新的 1帧 画面的后半段读取显示到屏幕上, 这就造成了我们开头的图片上的 撕裂现象。
垂直同步
- 为了解决双缓冲区造成的撕裂问题, GPU 又引入了一个新的机制 垂直同步 (简写 V-Sync) 。当开启垂直同步后, GPU 会等待显示器的 垂直信号(VSync) 发出后, 再去进行新的一帧的渲染和缓冲区更新。这样就解决了 画面撕裂现象, 也增加了画面的流畅度。但是需要消耗更多的计算资源, 也会带来部分延迟。
在视频控制器进行读取显示图像时,当当前这一帧的内容还未读取完成时,GPU将新的一帧内容提交到帧缓冲区并把两个帧缓冲区进行更新后,视频控制器就会把新的一帧数据的下半段显示到屏幕上,造成画面撕裂的现象。为了解决图像撕裂,引入了垂直同步信号和双缓存区
- 垂直同步信号
- 我们开启垂直同步,显卡绘制3D图形前会等待垂直同步信号,当该信号到达时,显卡开始绘制3D图形,如果显卡性能较为强劲,在下个垂直同步信号到来之前已经完成了对该帧的渲染,显卡就会暂停处理,等下个垂直同步信号到来后才开始渲染下一帧。通俗的来讲,垂直同步就是让显卡每秒输出的帧数等于显示器的刷新率。垂直同步是用来防止画面撕裂的,反之,关闭垂直同步就会出现撕裂、跳帧的情况。跳帧和撕裂形成原因是相同的,只是跳帧中显卡速度更快一些。垂直同步信号是给缓存区加把锁,从而降低显卡写入缓存区的速度。
- 双缓存区
- iOS是双缓冲机制,前帧缓存和后帧缓存,cpu计算完GPU渲染后放入缓冲区中,当gpu下一帧已经渲染完放入缓冲区,且视频控制器已经读完前帧,GPU会等待vSync(垂直同步信号)发出后,瞬间切换前后帧缓存,并让cpu开始准备下一帧数据。
- 如上图所示,此时由于处于初始状态,画图操作的结果都在后缓冲区中,而屏幕上显示的则是前缓冲区中的内容。此时画图操作尚未完成。画图操作结束,下一个画图操作的结果保存对象指向前缓冲区,屏幕的显示对象指向后缓冲区,此时前缓冲区变成实际意义上的后缓冲区,后缓冲区变成实际意义上的前缓冲去,即实现“页交换”操作。
谈谈掉帧的处理策略?
由于是因为CPU和GPU工作耗时导致的卡顿掉帧,所以可以从CPU和GPU两方面来进行优化,减轻两者的耗时工作。
- CPU:将CPU的工作放置到子线程完成。如对象的创建、调整、销毁;layout布局计算、文本计算;文本的异步绘制、图片编解码。
- GPU:避免离屏渲染。视图的圆角设置、阴影、蒙版、光栅化都会造成离屏渲染增加GPU工作量,可通过CPU的异步绘制机制来完成这类操作,从而减轻GPU压力。
CPU与GPU的工作
CPU的工作:
- layout:进行UI布局、文本计算。
- display:进行绘制。drawRect:方法就发生在这一步。
- prepare:进行图片编解码。比如imageView图片是不能直接显示到屏幕的,需要经过解码。
- commit:通过CoreAnimation框架提交绘制好的位图给GPU进行之后的渲染。
GPU的工作:
- CPU生成的位图进行渲染,显示到屏幕上
- GPU中通过顶点着色器、片元着色器完成对显示内容的渲染,将结果存入帧缓存区
- GPU通过帧缓存区、视频控制器等相关部件,将其显示到屏幕上
苹果的垂直同步+双缓冲区机制是什么?
为了更容易理解, 这里以 CRT 显示器进行说明。 为了显示图像, CRT 显示器的电子枪按照上图的方式, 从上到下进行逐行扫描, 全部扫描完成后显示器就会呈现出 1 帧画面, 随后电子枪会回到初始位置继续下一次扫描。
垂直信号
为了把显示器的显示过程和系统的视频控制器进行同步,显示器(或者其他硬件)会用硬件时钟产生一系列的定时信号。
- 当电子枪换到新的一行,准备进行扫描时,显示器会发出一个水平同步信号(horizonal synchronization),简称 HSync;
- 而当一帧画面绘制完成后,电子枪回复到原位,准备画下一帧前,显示器会发出一个垂直同步信号(vertical synchronization),简称 VSync。
双缓冲区
在最初的时候, 帧缓冲区只有一个, 这种情况下帧缓冲区的
**读取 和 刷新**
都会有比较大的效率问题。 为了解决效率问题, 显示系统后来引入两个缓冲区, 也就是 双缓冲机制 。这种情况下, GPU 会首先渲染好一阵放入到一个缓冲区内让视频控制器去读取, 当下一帧渲染好之后, GPU 会直接把 视频控制器 的指针指向 第二个缓冲区。这样一来效率得到了很大的提升。
简述iOS的渲染流程
![]()
第一步:CPU处理 对象的创建和销毁,对象属性的调整,布局计算,文本的计算和排版,和片的格式转换和解码,图像的绘制(CoreGraphics)
- 1.1 handleEvents,这一阶段主要处理事件的操作,比如用户的点击事件
- 1.2Commit Transcation,这一步主要分为4个阶段
- 1.2.1 Layout:包括LayoutSubViews,addSubView等
- 1.2.2 Display:主要用于视图绘制,drawRect方法
- 1.2.3Prepare:主要用于图像的解码转换等操作
- 1.2.4Commit:主要用于图层打包发送至RenderServer
- 1.3 RenderServer:这一步主要是通过OpenGL ES或者Metal来调度GUP进行渲染
**第二步:GPU处理 纹理的渲染第一步生成的数据是无法直接成像的,需要GUP进行数据的转换(顶点数据-顶点着色器-配置操作-光栅化-片元着色器-RenderBuffer),转换后的一帧的数据会存在我们的帧缓存区里也就是我们平常说的显存,对于苹果而言是双缓存机制(前帧缓存和后帧缓存) **第三步:成像 通过视频控制器从帧缓存区拿到数据后直接显示在屏幕上,对于苹果而言,想要显示一帧(一屏)的数据需要两个信号:水平同步信号(HSync)和垂直同步信号(VSync), 首先会发出一个HSync,逐个渲染水平方向的每一个像素,当一行渲染完成后,重新发出下一行的HSync,当一屏的所有像素都渲染完成后,会发出一个Vsync来从缓存区里获取下一帧的数据进行显示。
如何检测项目中的离屏渲染?
程序在真机上运行后,依次选择:Debug->View Debugging->Rendering->Color Offscreen-Rendered Yellow。
谈谈离屏渲染机制以及常见的触发离屏渲染的几种情况
离屏渲染(Off-Screen Rendering)是指GPU在当前屏幕缓冲区以外新开辟一个缓冲区进行渲染操作.
产生离屏渲染的原因就是一些图层不能直接绘制在屏幕上, 而是渲染到额外开辟的纹理中, 必须进行多个渲染的中间纹理结果进行预合成. 另外, 触发离屏渲染后这种转换发生在每一帧, 在界面的滚动过程中如果有大量的离屏渲染发生时会严重影响帧率。
触发离屏渲染的场景:
圆角 cornerRadius + masksToBounds
- 优化:贝塞尔曲线绘制圆角
- 优化:切图实现圆角+阴影
采用了光栅化的 layer (layer.shouldRasterize)
- 使用了 mask 的 layer (layer.mask)
- 需要进行裁剪的 layer (layer.masksToBounds /view.clipsToBounds)
- 设置了组透明度为 YES,并且透明度不为 1 的layer (layer.allowsGroupOpacity/ layer.opacity)
- 使用了高斯模糊
- 添加了投影的 layer (layer.shadow*)
- 绘制了文字的 layer (UILabel, CATextLayer, Core Text 等)
- (UIImage *)imageByRoundCornerRadius:(CGFloat)radius
corners:(UIRectCorner)corners
borderWidth:(CGFloat)borderWidth
borderColor:(UIColor *)borderColor
borderLineJoin:(CGLineJoin)borderLineJoin {
if (corners != UIRectCornerAllCorners) {
UIRectCorner tmp = 0;
if (corners & UIRectCornerTopLeft) tmp |= UIRectCornerBottomLeft;
if (corners & UIRectCornerTopRight) tmp |= UIRectCornerBottomRight;
if (corners & UIRectCornerBottomLeft) tmp |= UIRectCornerTopLeft;
if (corners & UIRectCornerBottomRight) tmp |= UIRectCornerTopRight;
corners = tmp;
}
UIGraphicsBeginImageContextWithOptions(self.size, NO, self.scale);
CGContextRef context = UIGraphicsGetCurrentContext();
CGRect rect = CGRectMake(0, 0, self.size.width, self.size.height);
CGContextScaleCTM(context, 1, -1);
CGContextTranslateCTM(context, 0, -rect.size.height);
CGFloat minSize = MIN(self.size.width, self.size.height);
if (borderWidth < minSize / 2) {
UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:CGRectInset(rect, borderWidth, borderWidth) byRoundingCorners:corners cornerRadii:CGSizeMake(radius, borderWidth)];
[path closePath];
CGContextSaveGState(context);
[path addClip];
CGContextDrawImage(context, rect, self.CGImage);
CGContextRestoreGState(context);
}
if (borderColor && borderWidth < minSize / 2 && borderWidth > 0) {
CGFloat strokeInset = (floor(borderWidth * self.scale) + 0.5) / self.scale;
CGRect strokeRect = CGRectInset(rect, strokeInset, strokeInset);
CGFloat strokeRadius = radius > self.scale / 2 ? radius - self.scale / 2 : 0;
UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:strokeRect byRoundingCorners:corners cornerRadii:CGSizeMake(strokeRadius, borderWidth)];
[path closePath];
path.lineWidth = borderWidth;
path.lineJoinStyle = borderLineJoin;
[borderColor setStroke];
[path stroke];
}
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return image;
}
为什么需要离屏渲染
- 一些特殊效果需要使用额外的 Offscreen Buffer 来保存渲染的中间状态,所以不得不使用离屏渲染。例如mask, 还有 UIBlurEffectView等
- 处于效率目的,如果是非常复杂的静态页面, 可以将内容提前渲染保存在Offscreen Buffer 中,达到复用的目的. 例如CALayer的shouldRasterize属性, 开启以后Render Server 会强制将 CALayer 的渲染位图结果 bitmap 保存下来,这样下次再需要渲染时就可以直接复用,从而提高效率
离屏渲染为何造成性能问题?
离屏渲染(Off-Screen Rendering)是指GPU在当前屏幕缓冲区以外新开辟一个缓冲区进行渲染操作.
通常情况下来说, 离屏渲染非常消耗性能, 主要在两个方面:
- 创建新缓冲区: 要想进行离屏渲染,首先要创建一个新的缓冲区(iOS使用双framebuffer策略, 这里创建的是除这两个buffer以外的缓冲区)
- 渲染的上下文切换: 进行两次上下文环境切换, 先切换到屏幕外环境, 离屏渲染完成后再切换到当前屏幕, 上下文的切换是很高昂的消耗。
图像显示过程
- CPU 计算好要显示的内容然后提交到 GPU
- 经过 GPU 渲染完成后, 渲染的结果会放入到 帧缓冲区 (FrameBuffer)
- 视屏控制器逐行读取帧缓冲区的数据, 经过可能的 数模转换 传递给显示器进行显示
KVO & KVC
KVO的实现原理
如何手动触发KVO
直接修改成员变量会触发KVO吗
通过KVC修改属性会触发KVO么?
KVC的赋值和取值过程是怎样的?
- 48. KVC的keyPath中的集合运算符如何使用?
- 49. KVC和KVO的keyPath一定是属性么?
- 50. 如何关闭默认的KVO的默认实现,并进入自定义的KVO实现?
- 45. addObserver:forKeyPath:options:context:各个参数的作用分别是什么,observer中需要实现哪个方法才能获得KVO回调?
Category分类
Category的使用场合是什么?
Category的实现原理?
Category和Class Extension的区别是什么?
Category有+load方法吗?+load方法是什么时候调用的?+load方法能继承吗?
Category有+initialize方法吗? +initialize方法是什么时候调用?+initialize方法能继承吗?
+load方法和+initialize的区别是?出现继承时,调用顺序?
Category能否添加成员变量?如果可以,如何给Category添加成员变量?
简述分类的作用域动态性
Block代码块
block的原理是怎样的?本质是什么?
block类型?
请问__block的作用是什么?有什么使用注意点?
block的属性修饰词为什么是copy?使用block有哪些使用注意?
block在修改NSMutableArray,需不需要添加__block?
使用block时什么情况会发生引用循环,如何解决?
在block内如何修改block外部变量?
使用系统的某些block api(如UIView的block版本写动画时),是否也考虑引用循环问题?
iOS block 的原理,block 的属性修饰词为什么用 copy,使用 block 时有哪些要注意的?
消息机制
_objc_msgForward 函数是做什么的,直接调用它将会发生什么?
load和initialize详解,中间做了什么事情,需要注意什么?
请讲一下OC中的消息机制?
objc中向一个nil对象发送消息将会发生什么?
objc中向一个对象发送消息[obj foo]和objc_msgSend()函数之间有什么关系?
什么时候会报unrecognized selector的异常?
isMemberOfClass 和 isKindOfClass的区别
objc中的类方法和实例方法有什么本质区别和联系?
以下打印结果分别是什么?
Runtime相关
什么是Runtime?平时项目中有用过嘛?
runtime如何通过selector找到对应的IMP地址?(分别考虑类方法和实例方法)
使用runtime Associate方法关联的对象,需要在主对象dealloc的时候释放么?
runtime如何实现weak变量的自动置nil?
能否向编译后得到的类中增加实例变量?能否向运行时创建的类中添加实例变量?为什么?
RunLoop相关
讲讲RunLoop, 项目中有用到吗?
讲讲Runloop常见的使用场景?
RunLoop内部实现逻辑?
RunLoop和线程的关系?
timer与RunLoop的关系?
程序中添加每3秒响应一次的NSTimer, 当拖动tableview时timer可能无法响应要怎么解决?
RunLoop是怎么相应用户操作的,具体流程是什么样的?
说说RunLoop的几种状态
RunLoop的mode作用是什么?
28. runloop和线程有什么关系?
29. runloop的mode作用是什么?
30. 以+ scheduledTimerWithTimeInterval…的方式触发的timer,在滑动页面上的列表时,timer会暂定回调,为什么?如何解决?
31. 猜想runloop内部是如何实现的?
定时器(Timer)
PerformSelector
GCD
事件响应
手势识别
界面刷新
网络请求
AutoreleasePool
runloop与线程的关系
事件循环机制
Runloop与NSTimer的关系
Mode、Source、Timer、Observer
常驻线程的实现
多线程相关
进程和线程的区别?同步异步的区别?并行和并发的区别?
何为线程安全?iOS中的各种锁性能与使用时机
40. GCD的队列(dispatch_queue_t)分哪两种类型?
41. 如何用GCD同步若干个异步调用?(如根据若干个url异步加载多张图片,然后在都下载完成后合成一张整图)
42. dispatch_barrier_async的作用是什么?
43. 苹果为什么要废弃dispatch_get_current_queue?
iOS 如果让你实现 GCD 的线程池,讲一下思路?
简述dispatch_once底层原理
谈下Objective C都有哪些锁机制,你一般用哪个?
iOS下如何实现指定线程数目的线程池?
多线程有哪几种?你更倾向于哪一种?
dispatch_barrier_async 的作用是什么?
你理解的多线程是?
请简单说明多线程技术的优点和缺点?
请简单说明线程和进程,以及他们之间的关系?
IOS多线程方案有哪几种?你更倾向于哪一种?
请简单说明主线程的作用,以及使用注意点?
请简单列出NSThread线程的几种状态,并说明状态转换的逻辑?
请简单说明如何简单的解决多线程访问同一块资源造成的线程安全的问题,以及注意点?
GCD和NSOperation的对比?
NSOperation和NSOperationQueue的好处有?
线程安全,线程同步方案?
自旋锁与互斥锁的比较?
atomic和nonatomic的区别?
多线程文件读写安全,多读单写?
使用CADispaly、NSTimer有什么注意点?
请问下面题的打印结果是?
- (void)viewDidLoad
{
[super viewDidLoad];
NSLog(@"1");
dispatch_sync(dispatch_get_main_queue(), ^{
NSLog(@"2");
});
NSLog(@"3");
}
内存管理相关
iOS 中内省的几个方法?
介绍下内存的几大区域?
什么是TaggedPointer?
讲一下你对IOS内存管理的理解?
ARC都帮我们做了什么?
方法里有局部对象,出了方法后会立即释放吗?
Copy和MutableCopy的区别?
copy和strong区别的区别?
weak指针的实现原理是?
什么情况使用 weak 关键字?,weak和assign的区别?
如何让自己的类用 copy 修饰符?如何重写带 copy 关键字的 setter?
用@property声明的NSString(或NSArray,NSDictionary)经常使用copy关键字,为什么?如果改用strong关键字,可能造成什么问题?@
synthesize合成实例变量的规则是什么?假如property名为foo,存在一个名为_foo的实例变量,那么还会自动合成新变量么?
在有了自动合成属性实例变量之后,@synthesize还有哪些使用场景?
objc使用什么机制管理对象内存?
ARC通过什么方式帮助开发者管理内存?
APP启动时,代码是怎么加载的,内存分了哪些区?
简述iOS内存管理机制
内存分区
循环引用
引用计数
自动释放池
弱引用表
堆和栈的区别?
- 栈区(stack)由编译器自动分配释放 ,存放方法(函数)的参数值, 局部变量的值等,栈是向低地址扩展的数据结构,是一块连续的内存的区域。即栈顶的地址和栈的最大容量是系统预先规定好的。
- 堆区(heap)一般由程序员分配释放, 若程序员不释放,程序结束时由OS回收,向高地址扩展的数据结构,是不连续的内存区域,从而堆获得的空间比较灵活。
property属性修饰
- 什么情况使用 weak 关键字,相比 assign 有什么不同?
在
ARC
中,在有可能出现循环引用的时候,往往要通过让其中一端使用weak
来解决,比如:delegate
代理属性。weak
关键字的作用是弱引用,所引用对象的计数不会增加,并在引用对象释放的时候自动被置为nil。weak
只可以修饰对象,assign
除了可修饰对象外,还可以修饰基本数据类型。weak
不会产生野指针,assign
修饰对象可能产生野指针,如果修饰基本数据类型则不会产生野指针。(因为值类型会被放入到栈中,遵循先进后出,有系统负责管理栈内存。而引用类型则会被放入到堆中需要自己手动管理内存)
autoreleasepool自动释放池
什么是自动释放池(@autoreleasepool)?
自动释放池(autoreleasepool)什么时候创建,什么时候销毁?
不手动指定autoreleasepool的前提下,一个autorealese对象在什么时刻释放?(比如在一个vc的viewDidLoad中创建)
苹果是如何实现autoreleasepool的?
xcode工具
Xcode项目打包生成ipa文件,Xcode都做了什么?(越详细越好)
点击一个app,系统做了什么?
Xcode执行run过程,做了什么工作?
xcode执行build操作,做了什么?
xcode执行archive操作,做了什么?
如何在Xcode构建任务前执行一段自定义脚本?
性能优化
App启动过慢,你可能想到的因素有哪些?
App启动过慢,你可能想到的因素有哪些?
调试
如何调试BAD_ACCESS错误
lldb(gdb)常用的调试命令?
BAD_ACCESS在什么情况下出现?
dSYM你是如何分析的
怎么防止反编译?
网络
HTTPS和HTTP的区别
HTTPS的连接建立流程
用户需要上传和下载一个重要的资料文件,应该如何判断用户本次是否上传成功和下载成功了?
iOS 为什么是三次握手?为什么是四次挥手?三次挥手不行吗?
iOS 讲一下 HTTPS 密钥传输流程?
GET和POST方式的区别
GET 相对 POST 的优势是什么?
1、最大的优势就是方便。GET 的URL可以直接手输,从而GET请求中的URL可以被存在书签里,或者历史记录里
2、可以被缓存,大大减轻服务器的负担
HTTP持久连接怎么判断一个请求是否结束的?
- Content-length:根据所接收字节数是否达到Content-length值
- chunked(分块传输):Transfer-Encoding。当选择分块传输时,响应头中可以不包含Content-Length,服务器会先回复一个不带数据的报文(只有响应行和响应头和\r\n),然后开始传输若干个数据块。当传输完若干个数据块后,需要再传输一个空的数据块,当客户端收到空的数据块时,则客户端知道数据接收完毕。