[iOS面试]第10章 架构框架相关面试问题
注意:本文主讲架构框架相关面试问题,包括图片缓存、阅读时长统计、复杂页面结构、客户端整体架构。
问题: 架构框架解决什么问题?
答:
- 引入架构框架为了实现
模块化
, 将各功能按模块进行划分 分层
解耦
降低代码重合度
一、图片缓存
1、图片缓存
问题:怎样设计一个图片缓存框架?
- 首先有Manager模块, 用以协调和调度框架内部各个模块
- 内存管理模块. 比如: 涉及图片缓存 就需要模拟计算机组成原理涉及到的多级缓存思想运用
- 图片磁盘缓存处理模块.
- 网络模块. 本地没有图片支持通过网络下载图片
以上构成基本图片框架,如果图片压缩, 保存图片需要解压缩的话,需要以下模块 - codeManager 解码相关管理者.
- 图片解码模块.
- 图片压缩/解压缩模块.
2、图片读写
问题:图片通过什么方式进行读写,过程是怎样的?
答:
- 以图片URL的单向Hash值作为Key, 存储到图片对应框架中
- 图片读取按照多级缓存读取图片,提交查找效率
3、内存设计
问题:内存的设计上需要考虑哪些问题?
答:
- 存储的Size. (内存存储空间大小)
- 淘汰策略. (有size限制, 后边再有新图片,需要有淘汰策略)
存储Size
需要考虑图片大小本身,以及不同图片大小的使用频率高低问题.
通过队列方式存取图片.
淘汰策略:考虑两种方案
- 以队列先进先出的方式淘汰
- 模拟计算机中LRU(Least Recently Used 最近最少使用)算法. (如30分钟之内是否使用过)
具体淘汰策略:
1>定时检查.
2>提高检查触发频率: 每次进行读写时 前后台切换时.
注意开销问题
补充: LRU算法是核心思想是:如果一个数据在最近一段时间都没有被用到,那么它在将来被使用到的可能性也很小。故当缓存空间已满的情况下,我们需要淘汰掉最久没有被访问到的数据。理想的LRU算法读写是时间复杂度应该都为O(1)。
4、磁盘设计
问题:磁盘设计需要考虑哪些问题?
- 存储方式
- 大小限制(如100MB)
- 淘汰策略(如某一图片存储时间距今已超过7天)
5、网络设计
问题:网络部分的设计需要考虑哪些问题?
- 图片请求最大并发量 (比如同一时间最大请求数量,限定在10张或者20张)
- 请求超时策略 (比如超时,可以采取重试机制再去请求图片, 2次再失败先不请求这张图片)
- 请求优先级 (比如下载或者缓存的图片是否当前用户最紧急使用, 如果是请求优先级高些)
6、图片解码
问题:对于不同格式图片,解码采用什么方式来做?
- 应用
策略模式
对不同图片格式进行解码
问题:在哪个阶段做图片解码处理?
- 磁盘读取后 (从磁盘读取是未解码,放到内存中最好解码完成, 因为系统在显示图片前会在主线程进行图片解码操作,减少主线程压力)
- 网络请求返回后
7、线程处理
二、阅读时长统计
1、框架设计
问题:怎样设计一个时长统计框架?
1)记录器: 对每一条时长统计数据进行记录
- 页面式记录器 :
常见场景:记录用户读取或者访问页面时长,一般从页面push开始作为阅读时长开始节点, pop后代表记录结束) - 流式页面记录器 :
比如浏览微博flow流以及腾讯新闻, 头条新闻,这种新闻的阅读记录, 每条定义为流式记录器 - 自定义式记录器 :
比如实际业务开发,有不同业务场景,微博, 腾讯新闻横滑式新闻条目的播放,由业务方控制具体控制开始结束的逻辑
2)记录管理者: 管理通过记录器记录的时长统计数据
- 记录缓存 :
- 磁盘存储 : 用来维护和处理异常场景,可能到时内存缓存丢失问题
- 上传器 : 用来将本地所记录下来的时长数据上传给server端
2、记录的缓存&存储
1)问题: 为何要有不同类型记录器,你的考虑是什么?
答: 基于不同分类场景提供的关于记录的封装, 适配
2)问题:记录的数据会由于某种原因丢失, 你是怎样处理的?
(考察降低丢失率, 不是每条都不丢失)
- 定时写磁盘
比如每满50条,进行磁盘写入 - 限定内存缓存条数(如10条), 超过该条数, 即写磁盘
3、记录上传器
问题: 关于延时上传的具体场景有哪些?
- 前后台切换
- 从无网到有网的变化
- 通用的轻量接口捎带
如果以企业级实践方式落地, 建议使用前两种是最优的, 最后有耦合在里边.
问题: 长传时机是怎样把控的?
答:
- 立刻上传
- 延时上传
- 定时上传
三、复杂页面结构
- MVVM框架思想
- ReactNative的数据流思想
- 系统UIView更新机制的思想
- FaceBook的开源框架AsyncDisplayKit关于预排版的设计思想
1、MVVM
2、ReactNative的数据流思想
任何一个子孙节点是没有权利做自己的变化更新的, 它必须要把自己变化更新的消息传递给根节点, 由根节点自顶向下方式询问哪些需要更新.由主动行为变为被动行为.
四、客户端整体架构
问题:你所在公司客户端整体架构是怎样的?如果让你设计,怎样设计客户端的整体架构?
独立App的通用层
比如通用层中可以有时长统计框架, 崩溃统计, 网络的第三方库. 这一层架构放到任何一个App中都可以起到底层支撑作用, 独立于APP通用业务层:
针对当前公司有某些通用的基础组件, 比如自定义布景控件, 特殊UIImageView的封装. 这些是和当前公司业务有关的, 对于整体App来说各个业务线对于通用控件都有需求,把这些内容沉降到通用业务层.中间层: 协调解耦作用
为了实现业务A 业务B 业务C 业务D的解耦各个业务代码
问题:业务之间的解耦通信方式
- OpenURL
- 依赖注入
中间层做业务A和业务C解耦, 业务C通过注入方式将自己注入到中间层, 业务A去中间层获取所依赖的方法或者成员变量.
例如: 中间层实现策略: 某一个业务方通过一个protocal注册到对应中间层中, 同时实现中间层代理方法返回给中间层一个具体实例对象. 业务A使用时, 可以通过事先和业务C商量的协议,从中间层中根据某一方法获取遵从某一协议的实例, 然后在业务A中把实例当做完全遵从协议透明对象来使用.