疫情期间比较火的《阿里、字节:一套高效的iOS面试题
》,以下是自己在2020年3月份做了一遍的结果,和盲点总结,欢迎大家交流.
以下题目有些比较简单的就没有作答.部分题目需要篇幅较长的,在《另外一篇博客》中有纯手写作答.
因为类也是对象,动态创建的时候object类(根类)的类就是meatclass
class_rw_t
的property_array_t
,它的内容是property_t
结构体,内容为name
和attribute
,对应属性,是成员变量的声明,在编译期前已经存在的属性会在编译期生成以_
为开头的同名成员变量,attribute
中是对成员变量的一些访问权限控制描述
class_ro_t 是编译期,编译器对类文件编译产生的,其中包含了类的方法,属性,协议等信息,它是不能被改变的,因为已经确定了大小
class_rw_t
中的信息中,如方法合并到method_list中等,这也是我们一直说类别方法是不是覆盖类中重名方法,而是在方法调用的时候会在method_list的中从后往前找,自然是category的先被找到,
通过@property定义的变量,只能生成对应的getter和setter的方法声明,但是不能实现getter和setter方法,同时也不能生成带下划线的成员属性
注意:为什么不能添加属性,原因就是category是运行期决定的,在运行期类的内存布局已经确定,如果添加实例变量会破坏类的内存布局,会产生意想不到的错误。
可以给类添加成员变量,但是是私有的
可以給类添加方法,但是是私有的
添加的属性和方法是类的一部分,在编译期就决定的。在编译器和头文件的@interface和实现文件里的@implement一起形成了一个完整的类。
伴随着类的产生而产生,也随着类的消失而消失
必须有类的源码才可以给类添加extension,所以对于系统一些类,如nsstring,就无法添加类扩展
不能给NSObject添加Extension,因为在extension中添加的方法或属性必须在源类的文件的.m文件中实现才可以,即:你必须有一个类的源码才能添加一个类的extension。
当类被装载的时候被调用,只调用一次
调用方式并不是采用runtime的objc_msgSend方式调用的,而是直接采用函数的内存地址直接调用的
多个类的load调用顺序,是依赖于compile sources中的文件顺序决定的,根据文件从上到下的顺序调用
子类和父类同时实现load的方法时,父类的方法先被调用
本类与category的调用顺序是,优先调用本类的(注意:category是在最后被装载的)
load是被动调用的,在类装载时调用的,不需要手动触发调用
当类或子类第一次收到消息时被调用(即:静态方法或实例方法第一次被调用,也就是这个类第一次被用到的时候),只调用一次
调用方式是通过runtime的objc_msgSend的方式调用的,此时所有的类都已经装载完毕
子类和父类同时实现initialize,父类的先被调用,然后调用子类的
initialize是主动调用的,只有当类第一次被用到的时候才会触发
优势: 让语言具有动态性,更加灵活,具有更多让程序员在运行时做动作的可能性.
劣势: 高度的动态话导致安全性降低,多层机制势必降低语言执行效率
自旋锁: 线程反复检查所变量是否可用,线程这一过程中保持执行,因此是一种忙等状态,一旦获取了,线程一直保持,直到显示的释放,自旋锁避免了进程上下文切换的开销,因此,对于线程只阻塞很短的场合是有效的.
互斥锁: 避免两个线程同时对某一变量进行读写,通过将代码切片成一个个临界区而达成
OSSpinLock已经被弃用,因为会出现低优先级线程持有锁,然后高优先级去获取锁的时候,spin lock会进入忙等状态,占用大量cpu时间,这时低优先级队列无法争夺cpu时间片,从而导致任务无法完成,无法释放lock
这个志向了一个静态变量,值为-1,是根据系统情况去分配他的数值.
视图&图像相关
定时器都是依赖runloop运行的,
NSTimer是最见的定时器,注意在使用的时候在滑动的时候不会被触发,需要加入到runloop commonmode 中,在没有runloop运行的子线程,也不会执行
有内存泄漏问题,注意invalied.提供了比较多的初始化方法.比较方便易用
CADisplaylink 是根据屏幕刷新频率处罚的定时器,苹果目前的屏幕刷新频率为60HZ,华为刚出了一个90HZ的以后可能这需要注意下改动,在不同的手机上是不同的频率,他比较准确,在没有什么耗时任务卡住runloop的情况下,很稳定,但是不灵活,适合做UI刷新,添加进runloop即刻启动
这时响应者链,事件传递链就是一层层翻上去,看看谁可以响应事件.
3.1,CoreGraphic基于Quartz高级绘画引擎,主要用于运行时图像绘制,开发者可以用来处理基于路径的绘图,转换,颜色管理,离屏渲染,图案,渐变和阴影,图像数据管理,图像创建和图像遮照以及PDF文档创建、显示和分析
3.2,CoreImage用于运行前创建的图像,大部分情况下CoreImage在GPU中完成工作,如果GPU忙,会使用CPU进行处理.支持两种处理模式
图形渲染管线,实际上指的是一堆原始图形数据经过一个输送管道,期间经过各种变化处理最终出现在屏幕的过程,通常情况下,渲染管线可以描述成vertices(顶点)到pixels(像素)的过程
关于图中详细解析,看链接内
CPU计算显示内容–>GPU渲染–>渲染结果放到帧缓冲区(iOS是双缓冲)–>视频控制器按照VSync信号逐行读取帧缓冲区数据,传递给显示器显示
加载后会由系统管理内存,内存占用比较小,对象释放,内存不会,多次加载相同图片不会重复加载.
适合小图片,频繁重复加载的场景
内存占用小,相同图片会重复加载,重复占用内存,对象释放,对应的内存也会释放.
适合大图片,不频繁重复加载的场景
2,图片处理(裁剪,边框等)
4,从磁盘读取数据到内核缓冲区
5,从内核缓冲区复制到用户空间(内存级别拷贝)
6,解压缩为位图(耗cpu较高)
7,如果位图数据不是字节对齐的,CoreAnimation会copy一份位图数据并进行字节对齐
以上4,5,6,7,8步是在UIImageView的setImage时进行的,所以默认在主线程进行(iOS UI操作必须在主线程执行)。
1,GPU处理完后会放入帧缓冲区,视频控制器定时读取缓冲区内容,给屏幕显示
2,如果缓冲区允许覆盖,那么就会产生丢帧,或者和面断层.不允许覆盖,就会丢帧
可以用双缓冲区,或者加大缓冲区的方案解决
慢的原因是因为主线程的工作量大,比如IO,大量计算
从启动周期每一步分析,优化
1,定时任务获取主队列的调用栈,0.002获取一次,记录每次获取的方法内容,对应方法时间累加
2,hook objcMsgSend方法 获取每个方法前后时间,记录时间,需要汇编,难度大
在一个VSync内GPU和CPU的协作,未能将渲染任务完成放入到帧缓冲区,视频控制器去缓冲区拿数据的时候是空的,所以卡帧
CADisplayLink 监控,结合子线程和信号量,两次事件触发时间间隔超过一个VSync的时长,上报调用栈
使用定时器,每隔一段时间获取一次电量,并上报
网络优化分为,提速,节流,安全,选择合理网络协议处理针对的业务(比如聊天的,用socket)
为了防止开发者的应用随意安装在手机上,用证书控制,只有经过苹果允许的应用才可以安装上,防止盗版什么的
这么做的目的是为了整个应用生态的体验着想,当然也有安全因素在里边.
只是列出一些iOS比较核心的开源库,这些库包含了很多高质量的思想,源码学习的时候一定要关注每个框架解决的核心问题是什么,还有它们的优缺点,这样才能算真正理解和吸收
JSPatch、Aspects(虽然一个不可用、另一个不维护,但是这两个库都很精炼巧妙,很适合学习)
Weex/RN, 笔者认为这种前端和客户端紧密联系的库是必须要知道其原理的
CTMediator、其他router库,这些都是常见的路由库,开发中基本上都会用到
请圈友们在评论下面补充吧
手动埋点:代码侵入,不好维护,无法线上动态,但是灵活
可视化买点:开发代价大,自定义程度低,灵活性差.好处就是的运营人员上手快.对业务发展由好处.
单例,工厂,MVC、MVP、MVVM、观察者,代理,装饰模式
设计一个图片缓存框架(LRU)
设计一个线程池?画出你的架构图
你的app架构是什么,有什么优缺点、为什么这么做、怎么改进
oc怎么实现多继承?怎么面向切面(可以参考Aspects深度解析-iOS面向切面编程)
哪些bug会导致崩溃,如何防护崩溃
app的启动过程(考察LLVM编译过程、静态链接、动态链接、runtime初始化)
沙盒目录的每个文件夹划分的作用
什么是中间人攻击?怎么预防
TCP的握手过程?为什么进行三次握手,四次挥手
栈由编译器申请空间大小,是固定的,连续的,对应线程是唯一的,快速高效,缺点是有限制,先入后出不灵活
堆区是通过alloc分配的,它的内存空间是动态的,由一个空闲内存空间指针链表维护,内存空间不连续,可以很大,但是容易内存碎片化.好处就是查询快.
###加密算法:对称加密算法和非对称加密算法区别
对于移动开发者来说,一般不会遇到非常难的算法,大多以数据结构为主,笔者列出一些必会的算法,当然有时间了可以去LeetCode上刷刷题
基本的动态规划题、贪心算法、二分查找
搜集不易,大家动动小手,点点关注呗!更多课程与资料,可加我的学习群
答案:算术运算符、比较运算符、逻辑运算符、赋值运算符
Python是纯粹的自由软件
Python具有丰富和强大的库
Python是一种面向对象的解释型计算机程序设计语言
答案:系统管理任务 、web编程 、自动化测试、大数据处理
A: 变量无需先创建和赋值而直接使用
B: 变量不必事先声明
C: 变量无需指定类型
D: 可以使用del释放资源
答案:函数内是局部变量 : 30 函数外是全局变量 : 0
A: 类定义了对象的属性,并提供了用于初始化对象的初始化程序和操作这些属性的方法
B: 对象是类的一个实例
D: 类的抽象是将类的实现和类的使用分离开来
A: 可以使用random模块中的shuffle函数将一个列表中的元素打乱
B: 可以使用下标运算符[]来引用列表中的一个独立元素
C: 可以使用for循环来遍历列表中的所有元素
D: 可以使用split方法来将一个字符串分离成列表
A: 可以使用sort方法对一个二维列表进行排序
B: 当给函数传递二维列表时,是将这个列表的引用传递给函数
C: 二维列表不能用来存储二维数据
A: 类的继承可以从现有的类派生出新类
B: 可以使用isinstance函数测试一个对象是否是一个类的实例
C: 多态意味着一个子类对象可以传递给一个需要父类类型的参数
D: 类之间常见的关系是关联、聚合、组合和继承
调用func()进行传参,其输出值为30的是:
答案:封装、继承、多态
答案:对象名 = 类名()
A: 一个元组是一个固定列表
B: 不能对元组中的元素进行添加、删除或替换
C: 由于元组是一个序列,所以序列的常用操作可以用于元组
D: 如果元组的所有元素都是不可变的,那么这个元组是不可变的
A: 类定义了对象的属性,并提供了用于初始化对象的初始化程序和操作这些属性的方法
B: 对象是类的一个实例
D: 类的抽象是将类的实现和类的使用分离开来
A: 类的继承可以从现有的类派生出新类
B: 可以使用isinstance函数测试一个对象是否是一个类的实例
C: 多态意味着一个子类对象可以传递给一个需要父类类型的参数
D: 类之间常见的关系是关联、聚合、组合和继承
答案:位置参数和关键字参数
A: 无参数,无返回值
B: 无参数,有返回值
C: 有参数,无返回值
D: 有参数,有返回值
C: del:?析构函数,释放对象时使用
答案:普通方法、静态方法、类方法
C: 内置的isinstance()函数以一个对象与一个类为参数,若该对象属于给定的类或属于给定类的基类,其值返回为Ture
D: 内置的repr()函数会对给定的对象调用__repr__()特殊方法,并返回相应结果
答案:矩阵A和矩阵B不能相加
C: 零矩阵满足:A+0=A,其中0是与A同型的零矩阵
A: 矩阵乘法不满足交换律,并不等于说对任意两个矩阵A与B,必有AB≠BA
B: 矩阵A≠0,且B≠0,则必有AB≠0
C: 若矩阵A和矩阵B满足AB=BA,则A,B有可能不同阶
D: 若矩阵乘积AB=0,有可能是A≠0且B≠0
A: 当n=m时,矩阵A称为n阶方阵
B: 所有矩阵都有逆矩阵
C: 所有矩阵都有转置矩阵
D: 对角线元素均为1,其余元素均为0的矩阵称为单位矩阵
答案:他的样本可能无法代表美国大学生总体
A: 容易产生真值偏离可能性,因为样本中的大多数学生未完成和返回调查
B: 提供了回应的学生可能未准确报告他们的满意度
C: 样本可能不足以代表所有30,000名学生,原因有很多
D: 学校应根据这些数据对课程进行重大变更
A: 随机样本存在偏见的概率较小
B: 随机样本通常比便利样本更容易获得
C: 随机样本对它们取自的总体更具代表性
D: 两种样本类型一样适用
A: 投一枚硬币,观察正面、反面出现的情况
B: 抛一枚骰子,观察出现的点数
C: 在一批灯泡中任意抽取一只,测试它的寿命
D: 记录某地昼夜的最高温度与最低温度
A: 试验的样本空间只包含有限个元素
B: 试验中的每个基本事件发生的可能性相同
C: 试验的样本空间包含无限个元素
D: 试验中的每个基本事件发生的可能性不同
A: 使用线程可以把占据长时间的程序中的任务放到后台去处理
B: 程序的运行速度可能加快
C: 使用多线程后运行速度一定线性增长
D: 线程在执行过程与进程执行过程完全一样
A: 根据从样本那里获取数据的容易度选择个体。
B: 根据其是否愿意回答你的问题选择个体。
C: 以选中概率相同的方式选择个体。
D: 以选中一个个体不会影响另一个个体被选中几率的方式选择个体。
A: NameError是:使用一个还未赋予对象的变量
答案:第一类错误(弃真错误)和第二类错误(受伪错误)
A: 使用线程可以把占据长时间的程序中的任务放到后台去处理
B: 线程在执行过程中与进程没有区别的
C: 线程不能够独立执行,必须依存在应用程序中,由应用程序提供多个线程执行控制
D: 使用多个进程的优势在于每个进程都是独立运行的
A: 提出原假设H0 ,确定备择假设H1
B: 构造分布已知的合适的统计量
C: 由给定的检验水平?,求出在H0成立的条件下的临界值 (上侧?分位数,或双侧?分位数)
D: 计算统计量的样本观测值,如果落在拒绝域内,则拒绝原假设,否则, 接受原假设。
A: 除字典类型外,所有标准对象均可以用于布尔测试
B: 空字符串的布尔值是False
C: 空列表对象的布尔值是False
D: 值为0的任何数字对象的布尔值是False
A: 支持面向对象的编程
C: 支持面向过程的编程
D: 支持内存的自动管理
A: 字符应该视为长度为1的字符串
B: 可以使用len()函数计算字符串的长度
C: 既可以用单引号,也可以用双引号创建字符串
D: 在三引号字符串中可以包含换行回车等特殊字符
C: len(dict)—计算字典元素个数,即键的总数
D: dict.copy()—随机返回并删除字典中的一对键和值
A: 一个元组是一个列表
B: 不能对元组中的元素进行添加、删除或替换
C: 由于元组是一个序列,所以序列的切片操作可以用于元组
D: 一个元组是一个字典
A: 类变量在整个实例化的对象中是公用的
C: python中,子类可以重写父类的方法
D: 类的私有属性不能在类的外部被使用或直接访问
C: del:?析构函数,释放对象时使用
答案:语法错误和逻辑错误
A: NameError是:使用一个还未赋予对象的变量
答案:[“0”,”1”,”2”,”3”]
答案:每行只有对角线位置的值非零,其它位置皆为0.
答案:转置矩阵就是把一个矩阵的的行换成同序号的列得到的一个新矩阵
函数可以返回值,也可以不返回值
样本统计量为 32,总体参数为 25。
样本中包含 1000 名居民。
如果我们使用更大的样本(例如,n = 10000),获得的样本均值往往更接近总体均值。
我们的样本均值和总体均值不同是不正常的,因为随机样本应保证 100% 的准确估计。
学校应根据这些数据对课程进行重大变更。
存在无应答偏倚可能性,因为样本中的大多数学生未完成和返回调查。
样本可代表所有30,000名学生,因为样本是随机挑选的。
样本可能不足以代表所有30,000名学生,原因有很多。
在函数定义的时候设置好
当调用传入其它值时,使用传入的参数值
默认参数不可以被传入参数替换
矩阵A的迹是特征值之和
numpy 是用来数值计算的库