本帖最后由 wangxiaoting 于 2018-11-6 13:48 编辑
iOS升级优化记录20181106 一、总览 本次升级优化的重点分为以下几个方面: 1、工程结构 2、代码书写规范 3、离线消息 4、数据库 5、网络链接 6、消息重发 7、消息转发 8、视图 二、详解 1、工程结构 随着项目的功能逻辑的改变、内容不断扩大,原来的工程结构显得有些混乱。为了利于项目的后期开发与维护,提高效率,我们对项目的结构重新做了调整。结构如下: (1)Base:基类,比如BaseViewController,BaseModel等 (2)Class:App中所有的模块功能,比如Chat、Login、Group等 (3)Manager: a、NetWorkManager:网络请求、缓存管理,下载管理 b、SocketManager:socket管理 c、ThirdFunctionManager:第三方功能管理(第三方功能尽可能的写到Manger里面,在用到的地方直接调用方法) d、SIMSDKManager:调用自己的接口与数据库管理 (4)DB:数据库 (5)Utilite: a、Categories:类别 b、Config:宏定义 c、Custom:自定义视图 d、ThirdLibraries:第三方库(第一选择pod,pod不可行再加到此文件夹) e、PCH:项目的pch文件 (6)Resource:资源文件,音频、视频、Plist文件 (7)Main:AppDelegate、main.c等
2、代码书写规范 不同的开发者,代码书写风格不同,虽然没有对错之分,但在团体项目开发中,不仅代码显得凌乱不堪,还不利于维护。为了保证app稳定性,保证开发效率,我们将代码书写规范统一风格。主要从以下几点进行了约束规范: (1)命名规则 a、常量的命名:采用小驼峰命名法(第一个单词全部小写,后面单词首字母大写)。 b、宏的命名 :以SIM字母作为前缀,后面采用大驼峰命名法。 c、枚举的命名 :遵循Objective-C内部框架定义方式。Enum中枚举内容的命名需要以该Enum类型名称开头。 d、类的命名 :以SIM字母作为前缀,后面对应类的全称。 e、方法的命名 :方法参数换行保持对齐。 f、属性和对象的命名 :采用修饰+类型的方式命名,BOOL类型添加is前缀,单词采用小驼峰命名法。 (2)注释 a、公开类方法注释:在.h文件中声明类方法,采用文档注释,要写明方法的具体作用,所有参数的含义以及返回的参数值。 b、私有的对象方法注释:在.m文件中实现对象方法,采用文档注释,要写明方法的具体作用,如果有参数和返回值,需要添加所有参数的含义以及返回的参数值。 c、方法内部逻辑代码注释:复杂逻辑代码在代码上方进行注释,注释方式采用双斜杠+单个空格+具体注释内容。 d、属性注释:采用文档注释,,要写明方法的具体作用。 e、标记:在函数分组和使用#pragma mark - 给重要逻辑代码添加标记。 (3)格式化 a、赋值: 在”=”号左右两边各间隔一个空格。 类方法或对象方法 方法的”+/-”号和左侧小括号间隔一个空格,大括号换行,上下大括号对齐。 b、属性声明:property和左侧小括号间隔一个空格,逗号和下一个属性修饰符间隔一 个空格,右侧小括号和属性类型间隔一个空格,属性类型和属性变量间隔一个空格。
3、离线消息 用户登录账号并连接socket成功后,会收到好友对其发送的离线消息。每条消息独立,当离线消息数量非常庞大时,数据库的插入、界面刷新操作频繁,APP就会卡顿。对此我们分为两步进行了优化。 (1)处理消息类型为1000的离线消息计数器。用户登录成功后,会接收到一条消息类型为1000的计数消息,而不是之前多个独立的消息。服务器经过合并统计之后,将所有的离线消息,按照FromId(消息发送者ID)、FromType(会话类型)统计出数量,并且分别将其最后一条消息的内容、时间赋值到计数消息中。手机端同时修改了消息处理逻辑,增加是否为离线消息计数器的判断。SessionModel也同时新增了两个unReadOfflineMessageNumunRead和OnlineMessageNum两个参数,分别记录离线消息和在线消息的未读数量,原本的unReadMessageNum改为adOfflineMessageNumunRead与OnlineMessageNum的总和。解析计数消息获取到来自不同好友的具体内容,显示在首页的session列表中。对用户来说,可以看到好友发来的消息数量以及最后一条消息的时间和内容。但此时,这些离线消息并没有真正的保存到手机上。化繁为简,这样极大减少了数据库的查询及界面的刷新操作,提高了页面的流畅度。 (2)发送消息类型为1001的离线消息的请求。用户进入到某个好友的聊天界面时,手机端给服务器发送一条获取该好友所有离线消息的请求。手机端获取到离线消息后,按照在线消息的处理方式,存储并显示所有消息。这时该好友的全部离线消息已从服务器发送至手机端。 4、数据库 SQLite数据库时iOS开发中经常使用的数据持久化方案,随着用户的增多,好友群组的创建,通信消息的频繁收发,对数据库的操作也相应的增多,此时频繁的更新,访问数据库,数据库会产生巨大的压力。在多线程操作时,如果数据库未操作完毕,其他线程再次访问则会造成程序的崩溃。为了解决此类问题,我们开始寻找多线程下安全操作数据库的解决方案 FMDB本身对多线程就有所考虑,其中FMDatabaseQueue就是为了解决数据库操作线程安全问题的。所以我们开始了解FMDatabaseQueue的使用原理并进行数据库操作的优化,每个数据库创建一个FMDatabaseQueue单例,这样多线程操作时,使用一个队列,当有数据库操作时将任务插入队列进行依次执行,这样就不会出现多个线程同时对数据库进行操作而造成数据库崩溃的问题。 但是在运用过程中,我们也发现在使用队列操作时,因为队列是串行执行的,因此FMDatabaseQueue中inDatabase的block并不能嵌套使用,否则就会造成死循环等问题,导致程序崩溃。所以在inDatabase的block中要注意数据库操作的嵌套使用问题。 总结: (1)防止数据库频繁操作打开关闭, 使用一个单例类操作数据库。 (2)避免同时操作一个资源使用FMDatabaseQueue队列串行方式,同时注意inDatabase的block的嵌套使用问题。 5、网络链接 在开发中,网络是必不可少的一部分,有网络请求的地方就必须得需要网络的支持,所以就必须在进行网络请求的时候知晓当前的网络连接状态,但是如果每一次的网络请求都进行一次当前的网络状态查询显然是不科学的,所以就需要来设置一个全局的网络查询方法,对当前的网络连接状态进行实时监听。 如果用iOS开发中自带的Reachability类来实现的话比较麻烦,因为要保证它处于实时监听的状态,而且在得到当前的网络状态之后就要发送全局通知,我们在这里用的是借助 AFNetworking框架里面的AFNetworkActivityIndicatorManager单例类来进行网络状态的实时监听,该方法写在APPDelegate中- (BOOL)application: (UIApplication *)application didFinishLaunchingWithOptions: (NSDictionary *)launchOptions 方法中调用,可以做到对全局的网络状态进行实时的监听。 在网络状态更改为没有网络状态链接情况下,更改SIMSocketMnager,socket管理中的网络标识 isConnect为NO,并发送通知消息 [[NSNotificationCenter defaultCenter] postNotificationName: @"NOsocketConnect" object:nil]; 6、消息重发 之前消息发送失败的状态显示为红色❗️标志,正在发送的状态为转的菊花标志。在网络链接断开重连时,消息重发后状态未更改的问题及其处理逻辑如下 (1)没有网络状态或者网络状态不好时,发送消息,消息状态为正在发送,app中显示为转菊花标志状态。 当消息发送成功后,将数据库中状态改为已发送,发送失败则把状态更改为失败。
同时发送通知给消息会话页面,通知其刷新消息发送状态标识 消息会话页面收到通知后修改消息发送状态并刷新当前Cell (2)消息发送失败处理和优化 消息发送失败如上所示:发送消息后,如果消息发送失败则发送通知,通知会话页面修改消息状态并刷新界面。 本次优化了在网络重新链接及点击红色❗️按钮后的重发消息处理。接收到断网通知后,启动计时器,检测是否网络已连接。如果网络已连接,则重新发送未发送成功的消息,并停止计算器。 这样消息在断网时和点击发送失败重发消息的处理就优化完成了。
7、消息转发 消息转发在项目中最直观的就是,长按消息后弹出“转发”按钮。其实,在好友详情中发送名片、收藏列表中发送某条消息等,只要不在聊天回话界面但需要发送并保持到本地的消息,都算是消息转发。之前的消息转发,需要先创建聊天回话界面,把需要转发的消息体作为参数传进来,进入到聊天界面后再发送消息,同时还要判断是否有消息转发并分别作出不同的处理。这个逻辑复杂,并且不是很合理。对此我们将消息发送这一步放在了创建聊天回话之前,先通过chatMessageManager将消息发送出去并保存到本地。到此,剩下的步骤就和直接查看回话的流程一样。再按照正常的逻辑创建聊天回话,查询本地Message数据库获取该回话的消息,并显示在界面上。除此之外,还将单条多条消息转发合并。之前的单条多条消息是用了两个方法处理并发送,但其实是一种逻辑。现在舍弃了单条发送消息的方法,将单条消息写成只有一个对象的数组,然后调用多条发送方法。
8、视图 在这一次的优化中,我们对涉及到UI界面的View以及ViewController做了优化处理。以前的项目中有大量的xib文件,xib为开发者提供了一种可视化开发方式,可以直观的看到UI界面布局,将所需的控件拖拽到相应位置即可,方便快捷。但当需求发生改变,xib文件改动行比较大,而且在处理国际化的时候,相对来说比较麻烦,不利于维护。所以,我们将一部分xib文件改为纯代码。并将直接写在ViewContrller控制器中UI抽离,单独写成View。同时,UI布局使用了SDAutoLayout,不仅语法相对简单,代码更便于后期的维护。
|