Xcode警告常见问题汇总

背景

近期公司的项目开启了SwiftObjC的混编,随之也将部分Xcode的警告选项做了开启。开启后发现多出了很多的警告问题,大部分是代码不规范引起的低级的错误。于是在团队里成立了一个清理小组,专门立项对这些警告问题进行清理。这里总结一下我们在清理过程中发现的一些常见问题。

Warning2Error

Xcode的警告可以通过设置编译选项变为编译错误,参考文章
具体操作方式如下:

-Werror: Turn warnings into errors.
-Werror=foo: Turn warning "foo" into an error.
-Wno-error=foo: Turn warning "foo" into an warning even if -Werror is specified.
-Wfoo: Enable warning foo
-Wno-foo: Disable warning foo
-w: Disable all warnings.

我们依靠人工的CodeReview很难做到没有遗漏,对于一些低级代码错误,还是需要借助自动化的方式来做,最好是在开发阶段实时报错提示,以此来避免出现低级失误,提高代码质量,守住研发底线。

所以这里先介绍将警告转换为错误的方法,在实际项目中对一些我们认为不应该出现的警告代码,设置为编译错误,减少这些风险代码的产生。这样的设置越早开启越好,在项目变大之后改起来成本会很高。

对于一些例外的情况,比如有的场景就是需要用一些会触发警告的代码,可以通过如下代码将Clang的诊断关闭:

#pragma clang diagnostic push  
#pragma clang diagnostic ignored "-Wunused-variable"  
    // 你自己的代码  
#pragma clang diagnostic pop

常见问题

1. NS_DESIGNATED_INITIALIZER

警告
  • 1: Method override for the designated initializer of the superclass '-init' not found
  • 2: Convenience initializer missing a 'self' call to another initializer
  • 3: Convenience initializer should not invoke an initializer on 'super
Clang选项

-Wobjc-designated-initializers
传送门

原因

以上3个警告是由于使用NS_DESIGNATED_INITIALIZER不规范引起的。具体分析见这篇文章

2. 方法形参命名重复

警告
  • Redefinition of method parameter 'x'
原因

原因比较简单,在实现方法时出现了相同名称的形参,触发场景如下:

- (void)callMethodWithA:(NSString *)a andB:(NSString *)a
{
  NSLog(@"%@", a);
}

这里有一点需要注意,在上述场景中,第二个变量a的值会被忽略,即优先使用顺序靠前的实参的值。

//这里实际打印的是first
[self callMethodWithA:@"first" andB:@"second"];

这种警告改起来也很简单,确保参数命名不同即可。作为开发人员出现这种错误是不应该的,但是在实际项目中我们的确看到有很多这种警告,这种低级错误应该编译报错,而不是简单的给个警告。(需要调研Clang是否支持将该种类型警告变为错误)。

3. 方法重复声明

警告
  • Multiple declarations of method 'x' found and ignored
Clang选项

-Wduplicate-method-match
传送门

原因

原因很直观,在类或者分类的声明中,出现了重复的方法名,触发场景如下:

@interface Warning : NSObject
- (void)callA;
- (void)callA;
@end
//或者分类中重复声明同一个方法
@interface Warning (Category)
- (void)callB;
- (void)callB;
@end

解决方案也简单,删除一个重复的命名即可,低级错误。

4. 无用变量

警告
  • unused variable A
Clang选项

-Wunused-variable
-Wunused-const-variable

传送门1
传送门2

原因

声明的变量未使用,这种情况多数是代码迭代,逻辑变更时,没有考虑到要删除不再使用的变量。

5. 不会执行的代码

警告
  • code will never be executed
Clang选项

-Wunreachable-code
传送门

原因

这个警告在我们项目中主要是在下面两个场景下触发:

//if 逻辑判断永远为false
if (a == b || c) {
  //原意是a == b || a ==c,c是某个大于0的整数,写法错误导致else内的代码得不到执行
}
else {
  // Warning
}

//方法逻辑不需要了,没有删除,为了省事直接前置return
- (void)someMethod
{
  return;
  //下面的代码逻辑不需要了
  int a = 1;
  NSLog(@"%d", a);
}
  • if 逻辑判断永远为false
  • 代码逻辑废弃,前置return

6. 方法有声明,没有实现

警告
  • method definition for A not found
Clang选项

-Wincomplete-implementation
传送门

原因

类的定义中声明了某个方法,但是并没有实现。一般在定义协议时会声明方法,由遵循该协议的类去实现具体的方法。但是在我们的实际项目中,常见的场景是定义了基类,声明了方法,却不提供默认的实现,而仅仅在头文件里加了注释,告诉使用者需要子类来实现。

@interface SomeBaseClass : NSObject
- (void)methodA; //由子类实现
@end

@implementation SomeBaseClass
//no mehtod implementation for methodA
@end

这样的用法有些不伦不类,既不是协议,也不是一个完整的类,很容易给使用者造成困扰。

7. 隐式强引用self

警告
  • block implicitly retains ‘self’; explicitly mention ‘self’ to indicate this is intended behavior
Clang选项

-Wimplicit-retain-self
传送门

原因

这个警告的常见出现场景是在block内部直接使用实例变量_instance这种方式:

@interface SomeClass : NSObject
@property (nonatomic, strong) NSString *name;
@end
@implementation SomeClass
- (void)someMehtod
{
  dispatch_async(dispatch_get_main_queue(), ^{
    _name = @"John"; //没有明确使用self,直接通过下划线访问
  });
}
@end

这种问题容易出现循环引用,需要block捕获self时,建议通过self->_name或者self.name的方式访问,不要直接访问_name,将你的意图通过代码明确的表达出来,提升代码的可读性及可维护性。

8. 协议的方法没有实现

警告
  • method A in protocol B not implemented
Clang选项

-Wprotocol
传送门

原因

遵循了协议B的某个类,没有实现协议B中声明的方法A。这个警告一般有两个场景会出现:

  • 没有实现协议中要求为@required的方法
  • 协议没有明确指定哪些方法是@optional的,默认情况下所有的方法都被认为是@required

这类警告要求我们在定义实现协议时,要规范化:即定义时要明确哪些方法是必需实现的,哪些方法是可选的;实现时要保证实现所有必需的方法。

协议毕竟只是一份声明,一些类可能声明了自己遵循某个协议,但是实际并没有实现相关协议方法。这种情况下协议方法的调用者在执行某个方法前,不能简单的通过conformsToProtocol来确保方法可调用,而是应该通过respondsToSelector的方式来确认方法可调用。

9. 类型不匹配

警告
incompatible-pointer-types
Clang选项

-Wincompatible-pointer-types
传送门

原因

这个警告是我们项目中发现最多的,原因很简单,就是变量类型不匹配,比如声明的UIImage *类型变量,接受的却是一个UIView *的返回值:

- (void)someMethod
{
  UIImage *imageView = [self getImageView];
}

- (UIView *)getImageView
{
  return [[UIView alloc] init];
}

在工程警告关闭的情况下,上述使用场景是不会报编译错误的,也不会有警告提示。开发人员在使用时没有意识到自己声明错类型了,依然将imageView当作UIView来使用,虽然在代码逻辑执行上没有什么问题,但是可读性、可维护性就相当差了。还有的案例如下:

@interface SomeClassA : NSObject
- (void)playWithVideoUrl:(NSString *)url;
@end
@implementation SomeClassA
- (void)playWithVideoUrl:(NSString *)url
{
 self.video.url = url;//video.url实际是一个NSURL类型的变量
 [self.video play];
}
@end

这里playWithVideoUrl对外声明的是需要传入一个NSString *类型的变量,但是内部实现时实际需要的是一个NSURL *的类型,之所以上述代码在测试阶段没有发现问题,是因为在外部使用者调用时,传入的也是一个NSURL *类型。简单来说错误的只有这个方法的声明,调用和实现两个部分都是按照预期进行的,这种错误给后续维护人员会带来很大的困扰。

我们的实际项目中关于NSArrayNSMutableArray来回赋值的类似例子有很多,一方面是对开发人员对类型的声明和实际传递不够关注;另一方面也是由于警告被关闭,对这类错误的容忍度很高,久而久之导致很多这种类型不匹配的问题出现,为后续进行警告清理带来很大的工作成本。所以强烈建议新的项目各种警告一定要开起来

总结

经过这次清理警告的过程,我认为一定要将警告重视起来,尤其是在团队协作的项目中,代码的质量也是团队的精神面貌的体现。总结起来有两点:

  • 严格的把低级错误,由警告设置为错误,在开发阶段就将问题暴露。
  • 在项目建立之初尽早的开启相关警告,避免问题积重难返。

最后也要建立起代码质量监控的手段,比如使用Sonar+SwiftInferOCLintSwiftLint等工具,定期的分析项目的代码质量并解决相关风险代码问题。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,189评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,577评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,857评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,703评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,705评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,620评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,995评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,656评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,898评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,639评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,720评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,395评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,982评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,953评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,195评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,907评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,472评论 2 342

推荐阅读更多精彩内容