使用 OCLint 自定义 MVVM 规则
source link: http://yulingtianxia.com/blog/2019/01/27/MVVM-Rules-for-OCLint/?amp%3Butm_medium=referral
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
最近在搞 iOS MVVM 框架,虽说是 N 年前就老生常谈的知识了,但设计模式毕竟是只一种规范,无法约束项目中所有程序员都去遵循。我做了个 OCLint 的自定义规则,对 ViewModel 运行静态检查。
然而过程中踩了不少坑,OCLint 的官方 Repo 早已失效,可以使用我修改后基于 LLVM 7 的版本: https://github.com/yulingtianxia/oclint/tree/llvm-7.0
伸手党也可以使用我写的 脚本 直接安装,已包含 MVVM 规则。
编译 OCLint
编译 OCLint 时,会先下载 LLVM 等项目。由于 LLVM 源码废弃了在 SVN 上的版本管理,将其迁移到了 Git 上,所以目前各种版本的 OCLint 都无法编译了。而且最新版本的 OCLint 还是基于 LLVM 5 的!我从作者的 Repo 那发现有 LLVM 7 的 branch,依然无法编译,只好自己动手改了。
虽然 Git 上的提交与历史 SVN 提交记录有映射,但是经过实践发现并不精准可信。编译时需要用到 llvm-project 下的 llvm,cfe 和 compile-rt,而且三个 repo 的 release 版本一定要一致。然而 LLVM 在 Git 上同一个 release 的代码却无法编译通过。更离谱的是即便 LLVM 在 GitHub 上把整个 llvm-project 作为一个 repo,依然无法将其 release 版本编译通过。
算了,Git 不靠谱,还是改下 OCLint 的代码,从官网直接下以前打包好的吧。
llvm = 'http://releases.llvm.org/7.0.0/llvm' clang = 'http://releases.llvm.org/7.0.0/cfe' clang_rt = 'http://releases.llvm.org/7.0.0/compiler-rt'
我把最终可以正常编译的 0.18.10 版本发了个非官方的 release 包,macOS 亲测 ok: https://github.com/yulingtianxia/oclint/releases/tag/0.18.10
嫌麻烦不想编译的,可以直接跑我提供的脚本来安装已经编译好的 0.18.10 版本。以前安装过 OCLint 旧版本的可以先备份下,因为会被覆盖安装。
wget --no-check-certificate -O install-oclint https://github.com/yulingtianxia/oclint/releases/download/0.18.10/install-0.18.10 chmod +x install-oclint ./install-oclint
自定义规则
网上有很多介绍如何编写自定义规则的文章,这里假设已经成功编译好 OCLint,总体流程如下。
创建规则
使用 oclint-scripts 文件夹下的 scaffoldRule 脚本创建一个新规则,并指定模板。注意规则名不需要带 “Rule”:
oclint-scripts/scaffoldRule MVVM -t ASTVisitor
生成调试工程
创建一个文件夹用于生成调试 Rule 的工程。我已经创建好了: https://github.com/yulingtianxia/oclint/tree/llvm-7.0/oclint-xcodeproject
运行 xcode-debug.sh 脚本即可使用 oclint-rules 文件夹的内容创建一个 Xcode 工程。因为这里是想调试刚刚创建的 MVVM 规则,所以选择 oclint-rules。理论上可以修改脚本参数使用其他文件夹创建 Xcode 工程。
#! /bin/sh -e cmake -G Xcode -D CMAKE_CXX_COMPILER=../build/llvm-install/bin/clang++ -D CMAKE_C_COMPILER=../build/llvm-install/bin/clang -D OCLINT_BUILD_DIR=../build/oclint-core -D OCLINT_SOURCE_DIR=../oclint-core -D OCLINT_METRICS_SOURCE_DIR=../oclint-metrics -D OCLINT_METRICS_BUILD_DIR=../build/oclint-metrics -D LLVM_ROOT=../build/llvm-install/ ../oclint-rules
每个规则都有对应的 Scheme,选择我们自定义的 MVVMRule,添加启动参数。 -R
传入自定义的规则名,这里使用调试工程生成的 Debug 目录。接着传入一个随便写的测试用文件 TestViewModel.m
,此文件所依赖的 Framework 等环境参数也需要传入。别忘了需要把我贴的绝对路径修改成你电脑上的路径。
-R /Users/yangxiaoyu/Code/oclint/oclint-xcodeproject/rules.dl/Debug /Users/yangxiaoyu/Code/oclint/oclint-rules-test/OCLintTest/OCLintTest/TestViewModel.m -- -x objective-c -isystem /Users/yangxiaoyu/Code/oclint/build/oclint-release/lib/clang/7.0.0/include -iframework /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk/System/Library/Frameworks -isystem /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk/usr/include
为了能够调试运行,还需要在 Scheme 的 Info 下选择 Executable 为编译好的 oclint 的可执行文件。oclint-0.18.10 文件由于后缀名问题不允许被选择为 Executable,删掉后缀名的数字就可以了。这样就可以无需重新编译 OCLint 直接运行调试了!
实现规则
在 MVVM 设计模式下,我想让 ViewModel 的属性都是只读的。因为我只想通过与 Model 的数据绑定来更新 ViewModel 的值,或是在其内部更新状态。现在我需要实现一个规则来找出那些非只读属性。
先找几个自带的规则例子看看,结合 Clang AST 文档 学习下各种数据结构的定义。如果不知道自己的测试代码如何下手,可以用 clang
命令将测试代码转化为 Clang AST :
clang -Xclang -ast-dump -fsyntax-only TestViewModel.m
思路是遍历每个后缀名为 ViewModel
类的 Interface 中的所有 Property,判断每个 Property 的 Attribute,如果包含 readwrite
就触发 warning。提高优先级可以产生 error。
/* Visit ObjCImplementationDecl */ bool VisitObjCImplementationDecl(ObjCImplementationDecl *node) { ObjCInterfaceDecl *interface = node->getClassInterface(); bool isViewModel = interface->getName().endswith("ViewModel"); if (!isViewModel) { return false; } for (auto property = interface->instprop_begin(), propertyEnd = interface->instprop_end(); property != propertyEnd; property++) { clang::ObjCPropertyDecl *propertyDecl = (clang::ObjCPropertyDecl *)*property; if (propertyDecl->getName().startswith("UI")) { addViolation(propertyDecl, this); } auto attrs = propertyDecl->getPropertyAttributes(); bool isReadwrite = (attrs & ObjCPropertyDecl::PropertyAttributeKind::OBJC_PR_readwrite) > 0; if (isReadwrite && isViewModel) { addViolation(propertyDecl, this); } } return true; }
集成到 Xcode
先放一张集成后的效果:
在 CI 运行静态检查可以减少一部分人工 Code Review 的成本,缺点是发现问题滞后,解决问题有一定成本。而如果在本地 Xcode 运行静态检查,则可把问题扼杀在摇篮之中,缺点是占用开发机资源。
如何在 Xcode 中集成 OCLint 静态检查,官方有很详细的文档,图文并茂: https://oclint-docs.readthedocs.io/en/stable/guide/xcode.html
美中不足的是 Xcode Run Script 欠一点火候,可以参考下下面我提供的脚本:
if which oclint 2>/dev/null; then echo 'oclint exist' else wget --no-check-certificate -O install-oclint https://github.com/yulingtianxia/oclint/releases/download/0.18.10/install-0.18.10 chmod +x install-oclint ./install-oclint fi if which xcpretty 2>/dev/null; then echo 'xcpretty exist' else sudo gem install xcpretty fi source ~/.bash_profile cd ${SRCROOT} xcodebuild clean xcodebuild | xcpretty -r json-compilation-database --output compile_commands.json oclint-json-compilation-database -- -report-type xcode
后记
我只是简单的写了一个 ViewModel 的规则来跑通和验证整个流程,其实 MVVM 设计模式里还有更多的规则需要实现,比如 ViewModel 中不能引入 UIKit
等。欢迎有兴趣的同学提 PR!
Reference
Recommend
-
222
让XCode自动CodeReview你的代码-OCLint使用 枣泥布丁· 2017...
-
39
Neat URL - 基于自定义规则,自动净化 URL 链接,删除垃圾参数,保留正常路由 - NEXT
-
30
工程代码质量,一个永恒的话题。好的质量的好处不言而喻,团队成员间除了保持统一的风格和较高的自我约束力之外,还需要一些工具来统计分析代码质量问题。 本文就是针对 OC 项目,提出的一个思路和实践步骤的记录,最后形成了一个可以直接用的脚本。如果觉得文章篇...
-
20
前言 代码安全扫描是指在不执行代码的情况下对代码进行评估的过程。代码安全扫描工具能够探查大量“if—-then—-”的假想情况,而不必为所有这些假想情况经过必要的计算来执行这些代码。 那么代码安全扫描...
-
5
apache RewriteMap MapSource自定义规则使用手记 10.1期间,一位朋友问我一个apache的 Rewrite规则中一个高级语法RewriteMap的用法问题。其想要实现的是这个功能,有个多用户的blog,用户访问的时候,是用三级域名访问的。比如http://cfc4n1.blog...
-
9
目标读者 一线工程师,架构师 预计阅读时间 15-20min :turtle: 完成阅读的收获 了解静态代码审核技术的原理 了解静态代码审核技术工作流 不得不提的 Clang
-
10
使用 ReactiveX 构建 MVVM李明亮等100万人斯拉夫传承者,嘴炮学家 最近在思考一些问题。
-
5
1. 什么是 MVVM Toolkit# 模型-视图-视图模型 (MVVM) 是用于解耦 UI 代码和非 UI 代码的 UI 体系结构设计模式。 借助 MVVM...
-
6
大家好,我是本期的微软 MVP 实验室研究员——陈锦华。微软 MVP ( Windows Development 方向),专注于 .NET 开发,有十多年的客户端开发经验。现在热衷于撰写博客,分享 WPF、U...
-
6
使用MVC、MVP、MVVM和FRP实现Android局域网群聊应用Androidarchitecture
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK