产品定位
定位移动社交,并将娱乐与生活服务相结合.
整体架构模块分析
QQ主要分为登录注册,消息,聊天,联系人,动态,侧边栏,设置等几大模块.其中消息模块和聊天模块是核心模块.好友动态及联系人属于次核心模块,延续了PC端的界面结构.
整体模块结构如下图所示:
整体通过模块化设计,数据和UI分离.包含消息,聊天等主要聊天功能的接口封装为独立Target.
通过长连接的方式,当有消息进来或发送消息的时候,进行相应UI更新.
为增强用户体验,消息,聊天,联系人,动态,侧边栏等都采用Native的开发方式,结合热更新技术对UI进行动态调整.
游戏,会员,装扮等个性化内容由于变幻多样,无法使用Native的方式"一劳永逸",故采用的是H5的方式.一般H5页面会牺牲部分用户体验,但QQ通过其强大的服务端支持,H5页面也能达到原生的流畅效果.
核心模块分析
登录注册以及主界面消息模块
登录问题需要考虑到以下几点:
- 被迫下线问题:如果在线状态下,其他设备登录,会及时发送当前设备下线通知,界面通过UIWindow展示通知Alert,不允许用户进行非登录操作. 启动App时会进行免登操作,这时和后台进行交互,如果有被挤下线,提示登录,否则进行免登处理.
- 是否允许电脑端和手机端同时在线问题:后台存储登录当前设备的信息,比如设备名称,型号等.如果设置允许电脑手机同时在线,后台将对手机和电脑同时提供服务支持,被迫下线问题将被区分单独处理.而如果不允许同时在线,那么被迫下线问题会把电脑,手机视为一体混同处理.
消息模块
消息模块的消息类型繁多复杂.
消息类型包括普通消息,群消息和系统消息.普通消息仅处理一对一聊天的情况,群消息处理群聊天情形.系统消息则根据用户自定义进行个性化推送.
- 消息类型处理:
逻辑处理放在后台,客户端只管拉取数据.接口给到消息类型,客户端通过多个CellID进行不同消息类型处理- 活动,比如抢红包:
后台发送抢红包通知,界面通过TabeleHeaderView进行活动展示,并修改下拉刷新功能,下拉刷新不再对当前消息界面进行刷新,而是对围绕红包弹幕进行功能改造.- 置顶问题:
QQ的置顶功能是信息存储在本地.将置顶的这一条数据保存到数据库,再次请求数据时将数据与数据库的进行对比,发现相同的就置顶 .这里应对数据结构进行模型和功能划分,使得置顶逻辑清晰易懂,否则后续涉及到和其他业务逻辑的对撞很容易让代码杂乱无章.
聊天模块
首先看看聊天中的多种消息类型:
具体如下所示:
聊天界面主要是针对多种类型消息的UI处理.各种消息类型组成一个独立的代码模块,这个模块对每种消息类型提供服务支持.
语音信息和图片信息涉及本地缓存,将语音的ID或图片的名称以及语音(图片)内容进行压缩处理并分别作为key和value进行本地化存储.其他信息进行数据库加密缓存起来.
时间处理方面,发送消息时间通过毫秒处理,并将发送时间一同发给服务器,服务器以发送的时间为准进行排序,而不以接收到消息时间为准.这样避免多个消息出现顺序错乱的现象.
聊天发送消息面板功能
这里每个面板功能都是对相关代码的高度封装.通过一个模块将这些功能做成"元件",通过工厂化模式进行对应调用.
-
语音
这里通过AVFoundation
封装一个语音模块,并添加长按手势,对不同手势信息进行发送,取消处理.同时,进行语音本地化存储. -
图片发送
这里选择图片部分使用一个横向的UITableView
,并且监听系统图片的变化情况,当系统图片增加时(比如这个时候截图),对TableView
进行刷新. -
戳一戳
本质是动态图片,当发送后,将动态图片展示到聊天框中,并相对应展示全屏效果.动态图片的处理可以使用SDWebImage
里关于动态图片的功能,或者自己代码进行实现.
在本地化过程中,将这些信息通过key的方式存储在数据库中,在展示聊天消息列表的时候,进行替换操作. -
动态图
动态图经由网络在线展示,使用UICollectionView
,使用SDWebImage
对图片进行下载并展示.发送时,和戳一戳进行类似处理,不过不会进行全屏效果展示. -
表情
腾讯对表情的封装早有见识,他把每个表情转化成Unicode编码的形式,在发送的时候使用对应编码发送.而在展示的时候,通过富文本的形式展示.
给一个表情键盘的例子: YHExpressionKeyBoard
另外,BBS
里也有相关表情的处理. -
其他功能
这些按钮控件都对应一个独立功能,此处不再赘述.
对性能优方面的思考
QQ软件庞大,如果不进行新能优化,使用体验将大大下降,无以支撑腾讯庞大的用户诉求.
- 网络请求使用
NSURLSession
,而不是使用NSURLConnection
,使用HTTP 2.0,提高请求速度. -
UITableView
高度提前计算并做缓存处理,cell
通过Frame或者FlexBox
方式进行设计,避免使用Masonry
或者NSLayoutConstraint
. - 服务器传过来的图片在服务器端进行相关裁剪处理,避免图片过大影响性能.
- 纯代码,不要使用
Xib
或storeBoard
- 用
ARC
管理内存 - 重用和延迟加载
views
启动速断性能优化
1.main()
函数之前的优化
- 删除无用的类,减少没有调用的
# import
- 减少无用的
category
- 减少不必要的
Framework
,特别是非系统的 -
check framework设为
optional和
required,如果该
framework在当前
App支持的所有
iOS系统版本都存在,那么就设为
required,否则就设为
optional,因为
optional`会有些额外的检查. - 删除无用的静态变量
- 将不必须在+load方法中做的事情延迟到+initialize中
2.main()
函数之后的优化
- 删除启动时各业务方打的log(因为每次用
NSLog
方式打印会隐式的创建一个Calendar
) - 梳理应用启动时发送的所有网络请求,是否可以统一在异步线程请求
- 不使用
XIB
-
didFinishLaunching
里的非必要代码进行延时加载或懒加载.