前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >iOS developer的良好习惯

iOS developer的良好习惯

作者头像
落影
发布2020-12-01 10:19:58
7240
发布2020-12-01 10:19:58
举报
文章被收录于专栏:落影的专栏

前言

隐藏细节,暴露抽象。

作为一名有追求的工程师,我们希望代码能够在版本迭代中逐渐优化而不是劣化;同时也会学习掌握更多的技巧和工具,去更好的设计、实现和组织代码。偶然看到一个apple工程师的分享,于是加上一些自己的经验和感受,做一些总结。

正文

一、代码组织
1、使用group

作为一名iOS工程师,Xcode应该是最熟悉的工具之一。旧版本的Xcode在新建一个目录时,只会作为创建一个引用,不会同时在相同的路径下去创建目录。新版本Xcode创建目录的时候都是以group的形式去创建,会在同级路径下去创建对应的目录。 比如下图,在创建New Group的时候,就会同样在Audio的目录下去创建一个New Group的目录。如果项目的代码是很久以前的Xcode创建的,最好检查一遍目录,使得Xcode的工程文件目录和实际的文件目录结构保持一致;如果项目是新Xcode创建则尽量在Xcode中创建group。

2、拆分大文件

如果项目有使用storyboard,则可以把较大的storyboard文件,通过引用的方式拆分成多个storyboard。这样能提升打开时的速度,也能使得多人协同开发时减少冲突的产生。 但是我经历过的项目都没有使用storyboard,大文件的矛盾更多是产生在.m文件,以一个我们项目中的文件为例:

这个2000行的.m文件并不是一蹴而就,而是随着十几个版本的迭代,逻辑不断增加,慢慢变大的文件。这也是我们常说的历史技术债务。技术债务产生的原因多种多样,可能是最开始的时候没有很好的框架设计,也可能是实现过程中有不规范的现象,又或者是多人协作开发导致的代码膨胀。当发现问题之后,就需要去偿还这个技术债务。

.m文件拆分首先需要把业务的核心逻辑梳理出来,抽象出来该模块的状态信息、关键参数,将外部业务在.m内添加的逻辑改为依赖.m提供的状态,而状态可以通过通知、消息等方式抛出去; 核心但是又内聚的逻辑可以使用xxLogic去封装,然后.m文件直接依赖该xxLogic;也可以将其聚合到.m文件的一个Category之中; 经过这番处理,.m文件能得到极大瘦身,而梳理完内外部依赖之后,后续再新增逻辑也不用去查看.m文件,而是依赖下面的.h文件。

3、重视Xcode的提示

保持Xcode工程设置是最新的,使用Xcode自带的性能优化。当Xcode弹出下面这个框的提示时,如果没有特殊诉求,apple工程师推荐点击Perform Changes按钮。

在编译的过程中,Xcode给出的warning可能在线上运行时就是一个Bug。建议在debug开发阶段,打开Treat Warnings as Errors选项;追本溯源,找到问题的根本原因,解决每一个编译期间的warning。

如果是已知问题,暂无解决方案,为了避免阻塞编译运行,可以使用xcode指令去忽略。(具体的warning类型可以在Xcode的Issue Navigator查看,快捷键是command+5)

代码语言:javascript
复制
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
// ingore code
#pragma clang diagnostic pop
4、去掉无用的代码

我们有时会提交一部分被注释代码,理由可能是代码现在不需要但下个版本可能会用到,临时注释一下,反正不影响运行。但是设想一下,如果团队里面每个人都有这个习惯,那么项目中是否会存在很多无用的代码?并且这个代码可能永远也不会有用武之地。 所以,果断地删除那些无用代码吧,即使真的有需要用到的时候,也可以通过代码的版本控制工具去找到那些历史代码。

二、代码管理

版本控制系统已经成为开发的必备工具之一。曾经svn也是版本管理的高效工具,Windows系统中的小乌龟(TortoiseSVN)非常好用。但是随着git的出现,svn已经被逐渐淘汰。

1、提交独立

一个复杂功能往往由多个需求点组成,开发过程也可能持续数天时间。可以把需求的提交拆分成多次,尽量使得单次提交独立,Xcode可以看到每一行代码的提交备注信息。 换位思考,我们希望从git的commit信息里面,看到这段代码的缘由。 点一下右边对应信息,选择show commit,还可以看到对应commit的具体内容。

一个人可以记住昨天为什么写这段代码,但很难记住一段数月乃至数年前的代码为何出现。

2、分支管理

为了保持开发阶段的便利,提供alpha分支,作为日常开发的合入分支;为了保证外网代码的可查,提供beta分支,作为版本发布的打包分支;当版本发布之后,还需要打tag记录对应版本,比如说release_1.0.0.10。 日常的需求开发(feature分支)、问题修复(bug分支)都是在非主干分支进行开发,最终再合入alpha分支。合入的要求根据团队实际情况,可以是分支验收完成再合入,也可以合入后统一验收。

3、Code Review

Code Review(代码审查,后面简称CR)是发生在分支合入的情况,是成熟开发团队必不可少的环节。CR有助于团队代码风格的统一,包括函数命名、变量命名、代码组织风格等。同时,CR要求代码具备一定的可读性,也要求单次提交不过包括过多改动。

三、文档
1、必要的注释

好的代码一目了然,能清晰描述逻辑,不需要注释来辅助描述。但是一段特殊逻辑,需要有注释来描述为何存在,以方便在改动之后去回归影响点。 比如说一段经典的dispatch_after 1秒的逻辑,这1秒可能是为了避免某些异常case,也可能是产品侧的需求要求。

2、对外方法的描述

平时的开发过程,除了注意变量和方法的命名要具有含义,对外提供方法的注释可以清晰描述需要的参数。比如说下面的一个方法:

在Xcode中选择对应的方法,按下快捷键option+?就可以看到该方法的描述,以及各个参数的要求。如果方法还没添加描述,则按下option+command+?自动生成待补充的描述。

3、文档积累

随着业务的发展,项目中代码不可避免的会快速膨胀,直接阅读代码会非常吃力。此时就需要有文档来辅助了解各个模块的情况。 文档应当避免对具体逻辑细节的赘述,更是和从整体的设计和考虑的因素出发,描述该模块是如何运行起来。同时在设计的过程,也应该基于之前的技术方案设计。

培养团队的写文档习惯,每个版本前期组织技术方案评审,由负责较为复杂需求的工程师准备一份技术方案的设计文档,可以达到事半功倍的效果。

四、便捷工具

大家提到Xcode的分析工具,第一反应往往是Instrucment中的工具集。但是实际开发中还有一些便捷工具。

1、Network Link Conditioner

模拟弱网络环境,以前是在手机的设置-开发者-Network Link Conditioner可以去设置,现在真机连接之后可以在Xcode中按下command+shift+1,选择对应的设备就可以选择具体的网络环境。

2、 Address Sanitizer

Address Sanitizer是内存错误检测工具,通过malloc/free增加标记实现。 比如说下面这一段代码,buf指针创建了1024内存,再手动释放,然后再去访问buf指针的元素。这段代码编译时正常,在运行时不一定会崩溃 ,有可能就会演化成一个偶现bug,难以定位。 在使用Address Sanitizer工具的时候,运行到130行时就会报错:Use of dealloccated memory

打开方式是在scheme选项中,勾选Address Sanitizer。

3、Thread Sanitizer

Thread Sanitizer是线程错误检测工具,可以检测到一些多线程数据访问的错误,比如说下面的代码。 sTestNum是静态全局变量,创建了多个线程去操作该变量,会触发Data Race

打开方式是在scheme选项中,勾选Thread Sanitizer。

Thread Sanitizer关注的是数据的多线程访问,通过记录内存的访问来实现,并不能定位到多线程的crash问题,比如下面这个crash:

4、Main Thread Checker

Main Thread Checker是多线程操作UI检查工具,UI操作只能在主线程执行,如果在子线操作则会触发警告。

打开方式是在scheme选项中,勾选Main Thread Checker。

5、Debug Gauges

在debug运行程序的时候,Debug Gauge能快捷地查看CPU、Memory、Disk、Network信息。

打开方式是Xcode按下command+7。

五、开发建议
1、最小依赖原则

一段逻辑的运行,往往需要外部的变量输入。有时候为了便捷开发,函数调用时候不会传递参数,而是通过全局变量、self指针等直接去获取需要的数据。但是这样会导致代码逻辑紊乱。在编码的时候,非常建议使用最小依赖原则:尽可能少的使用外部依赖。 以函数为例,一个xx逻辑处理的方法应该只依赖函数参数。这样函数的输入输出是固定的,即使函数放到其他地方,只要保证函数的输入不变,则逻辑的输出是不变的。 同理,除了函数还有view、model等等,尽可能少的去依赖外部数据、外部模块,则该处逻辑更加独立,更容易实现可以直接复用的view、model等等。

2、组件化&模块化

实现功能的时候,应尽可能去除耦合;特定功能组成的库就是组件,写新功能代码尽可能要往组件方向实现;而模块化指的是根据业务形态,把代码按照功能、业务进行聚合,相当于组合了各种组件和业务逻辑的库。 模块化和组件化等一个重要特点就是Pod化,将这些特定、独立的功能代码和业务代码从主工程中剥离,抽象出来业务需要的接口,再重新通过pod依赖引入主工程。在这个过程,不单单是把代码转移到Pod库,还需要做一些业务的解耦和依赖抽象。 好处也是显而易见: 开发上,模块化后各个业务相对独立,能够更加专注自己业务逻辑,即使业务出错影响面也比较可控; 效率上,模块化后可以做二进制组件,加快编译速度; 管理上,组件owner的意识更强,方便添加数据监控; 架构上,强迫面向接口编程,避免大量耦合的胶水代码。

总结

本文部分参考自 WWDC2019,结合一些工作经验,做了更适合自己的阐述。 自己也梳理了接下来一段时间的技术优化方向: 日常业务迭代,通过CR保证新增代码风格统一; 复杂业务需求,需要做技术方案评审,集思广益; 已有历史债务,小模块微整实现,大业务走专项重构,注意人力投入、业务影响和收益评估。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
  • 正文
    • 一、代码组织
      • 1、使用group
      • 2、拆分大文件
      • 3、重视Xcode的提示
      • 4、去掉无用的代码
    • 二、代码管理
      • 1、提交独立
      • 2、分支管理
      • 3、Code Review
    • 三、文档
      • 1、必要的注释
      • 2、对外方法的描述
      • 3、文档积累
    • 四、便捷工具
      • 1、Network Link Conditioner
      • 2、 Address Sanitizer
      • 3、Thread Sanitizer
      • 4、Main Thread Checker
      • 5、Debug Gauges
    • 五、开发建议
      • 1、最小依赖原则
      • 2、组件化&模块化
  • 总结
相关产品与服务
检测工具
域名服务检测工具(Detection Tools)提供了全面的智能化域名诊断,包括Whois、DNS生效等特性检测,同时提供SSL证书相关特性检测,保障您的域名和网站健康。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档