iOS APP优化

项目结构和架构

1.项目结构

项目结构分为两大类,第一为项目中所使用的文件目录分类,第二为项目中使用的第三方库

项目文件目录分类

总体设计思路将项目的目录分为业务模块,功能模块,配置文件模块对业务模块采用MVC的设计模式;

业务模块:项目内有有几大业务模块就分几类,绝大部分项目都可以按照tabbar来划分业务模块,然后增加注册登录等,这就构成了业务模块,对每个业务模块采用MVC模式.

功能模块:项目内所引用或者使用的功能模块,这块按照不同功能模块类进行细分,例如可以细分为分类、公共的UI组件,Utils文件(其中Utils文件可以包含网络,加密,common等文件)等等.

配置文件模块:存放pch文件,常量,宏定义等全局共用的文件.

可以用下图表示:

 

项目第三方库

优先推荐采用cocopods管理项目所引用到的开源库和私有库.

2.项目架构

项目逻辑基本都围绕了一条主线时,我们采用MVC已经可以很好的满足我们的需求,但是当业务逻辑日渐复杂的时候,我们单纯的采用Model View Controller这种编程模式已经不能很好的将业务逻辑与代码分离开,也就是解耦Decouple.

为了更好的将ViewController解耦,产生了Model View ViewModel这种编程模式,ViewModel层其实做了一层Model与ViewController中间的桥接,有利有弊,该模式会产生很多胶水代码,但是配合响应式编程框架(如ReactiveCocoa或者RxSwift),可以做到最大程度的解耦。适合与自己实际项目业务复杂程度的模式才是好的编程模式

如果项目业务很复杂、很多业务组件都通用,可以采用组件化编程,常用的一种就是采用CocoaPods将项目业务模块分拆成各种pod库,使用什么模块直接集成就好,再配合MVVM和响应式编程框架(如ReactiveCocoa或者RxSwift),可以做到最大程度的解耦。蘑菇街的组件化设计思路可以借鉴参考:https://www.cnblogs.com/oc-bowen/p/5885476.html

程序健壮性

..

1.在框架层面提供运行稳定性

加强单位测试的重要性,单元与单元之间不具有强烈耦合性,合适运用MVC,工厂模式,等设计方法,封装,集成和多态的面向对象的思想,这些均是程序在框架层面的控制,虽然简单,但意义重大,可保证每次批量用例执行时,整体上的稳定可.

2.在细节层面上的技巧提高健壮性

属性修饰符的正确使用,对于类不同的属性选用合适的修饰符;

合理布局函数的返回值,保证函数的值一直;

必要情况下使用Try…Except…处理;

从运行时角度出发,对可能存在的异常做消息转发等操作;

细节层面上的东西很多,在此只列举1,2,还需在开发中总结积累.

3.清理代码,去除冗余代码

很多时候,我们的代码都是迭代开发的。往往会罗列一些无用的函数,引入一些无用的类库。这些内容貌似无意义,但却是代码中的隐患。可能在后续的类库更新或者函数变更中爆炸。所以,代码要保持清理,对于无用的引用和定义,要加以清除。

崩溃处理

1.检测上传崩溃信息

利用友盟, bugly等第三方统计,或者自己编写的一套崩溃方法,上传崩溃日志,以便于对崩溃现象进行分析,改正.

  1. 针对崩溃现象的处理

通过使用NSSetUncaughtExceptionHandler注册自己的异常处理回调,发生崩溃时让程序显示的从容一点,不会直接闪退,可以弹出自己的崩溃异常界面,可以参考Bilibili的界面,比如说前方遇到高能反应之类,程序需要重启之类的,不会让用户感觉到很突兀得闪退了,也可以在收到崩溃日志后手动维护Runloop. 下面是一个样例.

// 1. 注册ExceptionHandler

+ (void)installUncaughtExceptionHandler {

   NSSetUncaughtExceptionHandler(&HandleException);

   signal(SIGHUP, SignalHandler);

   signal(SIGINT, SignalHandler);

   signal(SIGQUIT, SignalHandler);

   signal(SIGABRT, SignalHandler);

   signal(SIGILL, SignalHandler);

   signal(SIGSEGV, SignalHandler);

   signal(SIGFPE, SignalHandler);

   signal(SIGBUS, SignalHandler);

   signal(SIGPIPE, SignalHandler);

}

// 2. 处理崩溃信息

void SignalHandler(int signal) {

   // 1. 获取调用栈

   // 2. 处理异常

   // 3. App保活

   BOOL isContiune = TRUE; // 是否要保活

   CFRunLoopRef runLoop = CFRunLoopGetCurrent();

   CFArrayRef allModes = CFRunLoopCopyAllModes(runLoop);

   while (isContiune) {

       for (NSString *mode in (__bridge NSArray *)allModes) {

           CFRunLoopRunInMode((CFStringRef)mode, 0.001, true);

       }

    }

   CFRelease(allModes);

   signal(SIGABRT, SIG_DFL);

   signal(SIGILL, SIG_DFL);

   signal(SIGSEGV, SIG_DFL);

   signal(SIGFPE, SIG_DFL);

   signal(SIGBUS, SIG_DFL);

   signal(SIGPIPE, SIG_DFL);

}

2.利用热修复进行动态bug修复

在工程中集成JSPatch,实现热修复功能

APP性能调优,体验优化

1.懒加载的合适使用

懒加载适用于一些可能不会加载的页面,比如弹框、空数据页面之类的,使用得当可以避免内存暴涨,使用不好,比如在必定会弹出的页面中使用懒加载可能会在增加页面响应时间,所以使用懒加载一定要注意使用场景,避免产生副作用. 

2.避免使用重绘

重写drawRect 或者drawReact:inContext方法会默认创建一个图层上下文,图形上下文所需要的内存为图层宽* 图层高* 4字节,图层每次进行重绘时都需要抹掉内存重新分配,会产生巨大的性能开销

3.用户体验

UITableViewCell 使用不当造成滑动卡顿;

减少cornerRadius,maskToBounds诸如造成离屏渲染的方法的使用;

网络请求操作没有任何状态展示,比如加载框、按钮置灰等;

网络请求设置合理的缓存策略;

4.内存管理

合理使用属性修饰符,避免僵尸对象和野指针的产生;

利用aoturealese来降低内存峰值;

利用instrucment的leak来检测是否存在内存泄露等问题;

减少诸如imageNamed这类将导致内容永驻方法的使用;

内存管理要注意的地方很多,此处只列举一二.

5.选择合适的数据存储项

针对不同的应用和用户数据采用不同的数据存储,具体的数据存储选项如下:

NSUerDefaults, 使用XML, JSON, 或者plist, 使用NSCoding存档, 使用类似SQLite的本地SQL数据库, 使用Core Data;

同时对于数据存储位置也要合理选择,对于不用用处的数据存放在document,library,cache中的位置要明确.

6.加速启动时间

应用启动时尽可能做更多的异步任务,比如加载远端或者数据库数据,解析数据;

同时在预加载pch文件中减少引用;

去掉不必要在启动过程中执行的业务和操作.

7.关于webView的使用

减少使用Web特性,尽量使用WKWebView来替代WebView的使用;这样能极大的降低内存消耗.

8.合理运用多线程

合理运用多线程来提交运行效率,避免主线程阻塞.

其他方面

  1. 减少大量的第三方SDK的使用,尤其是臃肿庞大的SDK;
  2. 包上线时检查开发过程中弃用的图片资源,冗余代码,减少包体积;
  3. 项目中使用的图片在满足需求的条件下,尽量缩减存储大小;
  4. 通过编译项的选择减少包体积;

猜你喜欢

转载自blog.csdn.net/ling_fengxue/article/details/81663390