OCLint 规则查询 & 简单理解
Rule Category
| Rule Name | Name | 简单理解 |
|---|---|---|
| BitwiseOperatorInConditional | bitwise operator in conditional | OCLint认为位运算符可读性不好,不建议用位运算 |
| BrokenNilCheck | broken nil check | 无效的nil检查,结果往往存在问题 |
| BrokenNullCheck | broken null check | 无效的null检查,可能会使程序崩溃 |
| BrokenOddnessCheck | broken oddness check | 对奇数进行检查(x % 2 == 1)不适用于负数,应使用(x & 1 == 1)或者(x % 2 != 0)
|
| CollapsibleIfStatements | collapsible if statements | 两个连续if语句的条件可以合并的应该合并,可以提高可读性,使代码整洁。 |
| ConstantConditionalOperator | constant conditional operator |
条件运算符的条件永远为true或false,令人困惑 |
| ConstantIfExpression | constant if expression |
if语句的条件始终为true或false,令人困惑 |
| DeadCode | dead code | 存在永远不会被执行的代码 |
| DoubleNegative | double negative | 使用双重否定是没有意义的 |
| ForLoopShouldBeWhileLoop | for loop should be while loop | 在某些情况下,可以将某些for循环简化为while循环,以使代码更简洁 |
| GotoStatement | goto statement |
goto语句被认为是有害的,慎重使用 |
| JumbledIncrementer | jumbled incrementer | 混乱的增量器通常是错别字。如果不是笔误,那么代码阅读起来是非常混乱的 |
| MisplacedNilCheck | misplaced nil check |
nil 判断 放错位置,逻辑短路 |
| MisplacedNullCheck | misplaced null check |
null 判断 放错位置,可能会程序崩溃 |
| MultipleUnaryOperator | multiple unary operator | 多重一元运算符不易理解,应简化 |
| ReturnFromFinallyBlock | return from finally block | 不建议从finally代码块中return
|
| ThrowExceptionFromFinallyBlock | throw exception from finally block | 从finally代码块中抛出异常,可能会掩盖其他异常或代码缺陷 |
| Rule Name | Name | 简单理解 |
|---|---|---|
| CallingProhibitedMethod | calling prohibited method | 当一个方法用__attribute__((annotate("oclint:enforce[prohibited method]")))标记时,禁止被调用(ps:不清楚使用场景) |
| CallingProtectedMethod | calling protected method | 当一个方法用__attribute__((annotate("oclint:enforce[protected method]")))标记时,它将是受保护的。在Objective-C中虽然没有protected这个概念,但是在设计的角度,我们有时希望一个方法只希望被它自己或者它的子类调用。这个方法可以模仿protected在有人调用的时候给一个警告 |
| MissingAbstractMethodImplementation | missing abstract method implementation | 当一个方法用__attribute__((annotate("oclint:enforce[abstract method]")))标记时,如果该方法没有具体实现,可以检测出来 |
| MissingCallToBaseMethod | missing call to base method | 当一个方法用__attribute__((annotate("oclint:enforce[base method]")))标记时,其实现都必须调用super类的该方法 |
| MissingHashMethod | missing hash method | 当isEqual方法被重写时,hash方法也必须重写 |
| Rule Name | Name | 简单理解 |
|---|---|---|
| AssignIvarOutsideAccessors | ivar assignment outside accessors or init | 检查是否在getter、setter、init method以外的方法对成员进行赋值 |
| AvoidBranchingStatementAsLastInLoop | avoid branching statement as last in loop | 在循环最后加入分支语句可能是个bug,负责理解起来比较困难,很大程度上会遗忘一些事情,导致一些错误 |
| DestructorOfVirtualClass | destructor of virtual class | 虚拟类的析构函数必须是虚拟的(ps:不太理解) |
| InvertedLogic | inverted logic |
倒置逻辑难以理解(例如:(!i ? -1 : 1))应改为(i ? 1 : -1)
|
| MisplacedDefaultLabel | ill-placed default label in switch statement |
switch语句中,default应放在最后的位置,否则令人困惑 |
| MissingBreakInSwitchStatement | missing break in switch statement |
switch语句中缺少break,很可能导致错误 |
| MissingDefaultStatement | missing default in switch statements |
switch语句中缺少default的情况,当switch语句未覆盖所有可能得情况时,必须要有default标签 |
| NonCaseLabelInSwitchStatement | non case label in switch statement | 当标签成为switch语句中的一部分时,非常令人困惑 |
| ParameterReassignment | parameter reassignment | 大多数情况下,对传入的参数进行重新赋值可能会造成问题 |
| PreferEarlyExit | prefer early exits and continue | 有return时,尽量让return提前,可以更轻松地理解代码(ps:参考例子) |
| ProblematicBaseClassDestructor | base class destructor should be virtual or protected | 基类的析构函数,要么是public和virtual的,要不是protected和nonvirtual的 |
| TooFewBranchesInSwitchStatement | too few branches in switch statement |
switch语句中的分支太少,可以用if语句代替,提高可读性 |
| UnnecessaryDefaultStatement | unnecessary default statement in covered switch statement | 当switch语句涵盖所有可能的情况时,不需要default标签,应将其删除 |
| Rule Name | Name | 简单理解 |
|---|---|---|
| AvoidDefaultArgumentsOnVirtualMethods | avoid default arguments on virtual methods | 避免给虚函数设置默认参数,给虚函数设置默认参数会破坏多样性和引起不必要的层次结构发杂性 |
| AvoidPrivateStaticMembers | avoid private static members | 避免使用私有静态成员,静态成员很容易破换封装性 |
| Rule Name | Name | 简单理解 |
|---|---|---|
| EmptyCatchStatement | empty catch statement | 空的catch,捕获了异常,但在未进行任何处理 |
| EmptyDoWhileStatement | empty do/while statement | 空的do-while语句 |
| EmptyElseBlock | empty else block | 空的else语句 |
| EmptyFinallyStatement | empty finally statement | 空的finally
|
| EmptyForStatement | empty for statement | 空的for循环 |
| EmptyIfStatement | empty if statement | 空的if语句 |
| EmptySwitchStatement | empty switch statement | 空的switch语句 |
| EmptyTryStatement | empty try statement | 空的try
|
| EmptyWhileStatement | empty while statement | 空的while语句 |
| Rule Name | Name | 简单理解 |
|---|---|---|
| UseBoxedExpression | use boxed expression | 检测出可以使用框式表达式代替的地方,更加简单易读(例如:[NSNumber numberWithInt:(43 - 1)] 改为 @(43 - 1)) |
| UseContainerLiteral | use container literal | 检测出可以使用容器字面量代替的地方(例如:[NSArray arrayWithObjects:@1, @2, @3, nil] 改为 @[ @1, @2, @3 ]) |
| UseNumberLiteral | use number literal | 检测出可以使用数值字面量代替的地方(例如:[NSNumber numberWithInt:42] 改为 @42) |
| UseObjectSubscripting | use object subscripting | 检测出可以使用下标访问代替的地方(例如:[arr objectAtIndex:0] 改为 arr[0]) |
| Rule Name | Name | 默认 | 简单理解 |
|---|---|---|---|
| LongVariableName | long variable name | LONG_VARIABLE_NAME=20 | 变量名称太长,影响可读性 |
| ShortVariableName | short variable name | SHORT_VARIABLE_NAME=3 | 变量名称太短,难以理解其含义 |
| Rule Name | Name | 简单理解 |
|---|---|---|
| RedundantConditionalOperator | redundant conditional operator | 冗余的条件运算符,应简化 |
| RedundantIfStatement | redundant if statement | 冗余的if语句,应简化 |
| RedundantLocalVariable | redundant local variable | 多余的局部变量,可以省略 |
| RedundantNilCheck | redundant nil check | 多余的nil 检查,因为在OC中向nil发送任何消息都会返回空值 |
| UnnecessaryElseStatement | unnecessary else statement | 如果if中已经带有return,则不需要写else语句 |
| UnnecessaryNullCheckForDealloc | unnecessary null check for dealloc | 在dealloc中不需要判空,就能删除元素(ps:不清楚发生场景) |
| UselessParentheses | useless parentheses | 无用的括号 |
| Rule Name | Name | 默认 | 简单理解 |
|---|---|---|---|
| DeepNestedBlock | deep nested block | NESTED_BLOCK_DEPTH=5 | 代码块嵌套层数太深 |
| HighCyclomaticComplexity | high cyclomatic complexity | CYCLOMATIC_COMPLEXITY=10 | 高圈复杂度,由决策点数量来决定,例如if, while, for(ps:if内的多个判断组合都会计算个数) |
| HighNPathComplexity | high npath complexity | NPATH_COMPLEXITY=200 | 高npath复杂度,NPath的复杂性取决于各种可能的执行路径数 |
| HighNcssMethod | high ncss method | NCSS_METHOD=30 | 方法有效代码行数太多(ps:block内的代码不算) |
| LongClass | long class | LONG_CLASS=1000 | 类的实现代码行数太多 |
| LongLine | long line | LONG_LINE=100 | 单行太长,可读性差 |
| LongMethod | long method | LONG_METHOD=50 | 方法行数太多(ps:空行也算在内) |
| TooManyFields | too many fields | TOO_MANY_FIELDS=20 | 字段太多 |
| TooManyMethods | too many methods | TOO_MANY_METHODS=30 | 方法太多 |
| TooManyParameters | too many parameters | TOO_MANY_PARAMETERS=10 | 参数过多 |
| Rule Name | Name | 简单理解 |
|---|---|---|
| UnusedLocalVariable | unused local variable | 已声明但未使用的局部变量 |
| UnusedMethodParameter | unused method parameter | 未使用的方法参数(ps:代理方法的参数不一定用到,可以忽略掉此规则) |
自定义阈值 & 理由
-
LongVariableName
默认:LONG_VARIABLE_NAME=20
OC命名规范在于完整、清晰,因此很容易出现较长的命名,例如UIApplicationWillChangeStatusBarOrientationNotification(都55个字符了),OCLint的变量命名长度规范默认为20,在OC中显然很多命名都不符合OCLint的规范,可以将此规范阈值改高一写,当然自己在命名时也不要毫无保留地随意用特别长的命名。
PS:写一门语言,就按该语言的习惯来写代码,否则各种不同习惯的代码混杂在一起很难受,现状就是这样。很反感有些以前写其他开发语言的同学在写OC时带上其他语言的习惯,例如函数命名、变量命名都喜欢缩写,阅读他们的代码还得去猜这个函数、变量是干什么的。
-
LongLine
默认:LONG_LINE=100
此规则初衷是不希望一行代码太长,正如前面所说,由于OC的命名习惯,很容易超出OCLint的默认限制,但是调用系统方法就很容易超出限制,因此可以将此规范阈值改高一些。
-
LongMethod
默认:LONG_METHOD=50
我们希望一个方法内不要做太多事,保证单一职责原则,因此OCLint添加了此规范限制,而这个限制连同空行也计算在内,50行的限制也太少了,在规范自己代码的同时,可以适当提高一下此限制。
-
HighNcssMethod
默认:NCSS_METHOD=30
此规则是限制方法的有效行数,同样的,在规范自己代码的同时,可以适当提高一下此限制。
-
HighCyclomaticComplexity
默认:CYCLOMATIC_COMPLEXITY=10
此规则为高权复杂度,由if、while、for等决策点来决定的,实际项目中业余逻辑复杂,各种判断的决策点太多,可以适当提高此规范限制的阈值,当然最重要还是拆分简化方法。
个人存在疑问的规则
-
PreferEarlyExit
不错,一般可以将return提前的尽量提前,阅读者可以更好地理解其中的逻辑,但这个规则会使很多getter、init方法报警告,此时还有必要将return提前吗?对于getter、init方法我是更倾向于苹果默认的写法。
但我又不想忽略此规则,因为其他方法,我更认可将return提前。
有什么优雅的处理方式吗?或OCLint的作者在这个问题上是否有什么想法?
-
ParameterReassignment
对于Objective-C上,在方法内对入参进行重新赋值,并不会影响调用者传入的原数据,自己也做过测试验证。
可能此规则是针对其他语言而言的,但还是想确认一下,在Objective-C中是否有必要使用此规则?否则的话我将选择忽略此规则。希望有知道的大神不吝赐教!
-
AvoidBranchingStatementAsLastInLoop
根据官方文档和网友对此规则的解释,循环最后不能加分支语句(即 continue、break、return?)。
对此我不太理解,为什么不可以?有时候代码逻辑就必须那样写啊!还是说为了迎合着个逻辑,要用更复杂的代码来避免(例如增加BOOL变量,在循环外面判断后再return)?