强迫症自述:做一个0警告的项目
前言
历经两个月,我终于完成了第一个C端项目全民星跑,整个工程总共8万行代码(包含注释行).作为强迫症的我把这个项目整的一个警告都没有,有人问我是不是因为我做了什么屏蔽工作,一键屏蔽什么的,其实这根本不存在的,其实我在开始架构整个工程的时候,就开始注意警告的个数了,加上大部分的控件三方都是自己写的,所以只要出现警告也是容易解决的,然后到项目的最后上线的时候,工程已经没有任何警告了.
有人会问,那么工程没有警告到底有什么好处呢?我知道的只有一个好处,那就是在项目编译的时候是非常的快,因为编译警告也是需要时间的.(PS:此处的好处未经过证实....)
全民星跑代码行数为8万行屏蔽警告
因为项目中我很少用到其他的三方,大部分是我自己写的,有用到的三方比如高德地图也是最新版本的,所以我很少用到屏蔽警告,但是我在做老项目版本迭代时候用到过屏蔽警告,主要是因为如果我随意篡改工程的话,可能会影响工程的功能,所以有些问题我只屏蔽了,还有的是一些三方的支持版本过低,或者是版本过时,做版本迭代的这个项目AFNetworking是2.5版的(早不知道过时多长时间了... ) 全部让我手动改成AFNetworking3.0了,像这种比较常见的三方我还是建议不用屏蔽,直接手动升级到最新版本吧!
下面我就说几个最常见的警告解决方案.
先说一个#pramark
预指令屏蔽警告方式,具体格式如下所示.
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-相关命令"
// 你自己的代码
#pragma clang diagnostic pop
忽略方法被弃用的警告(-Wdeprecated-declarations)
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
UIAlertView *alerView = [[UIAlertView alloc]initWithTitle:@"忽略警告" message:@"忽略警告" delegate:self cancelButtonTitle:@"取消" otherButtonTitles: nil];
#pragma clang diagnostic pop
忽略不兼容指针类型的警告(-Wincompatible-pointer-types)
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wincompatible-pointer-types"
//code这里插入相关的代码
#pragma clang diagnostic pop
忽略循环引用的警告(-Warc-retain-cycles)
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-retain-cycles"
self.completionBlock = ^ {
self.skScene = [SKScene sceneWithSize:self.videoNode.size];
};
#pragma clang diagnostic pop
忽略定义变量未使用的警告(-Wunused-variable)
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunused-variable"
int i = 1;
#pragma clang diagnostic pop
忽略selector中使用了不存在的方法名的警告(-Wundeclared-selector)
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wundeclared-selector"
UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
[button addTarget:self action:@selector(buttonAction) forControlEvents:UIControlEventTouchUpInside];
#pragma clang diagnostic pop
除了上面的警告之外,我们经常会遇到一些三方最低支持版本比我们预设的项目版本要高很多,就会爆出如下的警告.
Object file(三方静态库中的源文件) was built for newer iOS version(三方版本) than being linked (工程版本)
这个警告屏蔽起来比较简单,我们只需要在Build Settings ->Other Linker Flags中添加上一个-w字段即可.
还有就是我们会遇到如下警告.这表示是查询 Library 的时候出现的异常。
"directory not found for option '-L/..."
我们只需要在Project -> targets -> Build Setting -> Library Search Paths中找到对应的文件名删除即可.
和上面的警告类似,我们在查询 Framework 的时候也会出现异常。
"directory not found for option '-F/..."
我们只需要在Project -> targets -> Build Setting -> Framework Search Paths中找到对应的文件名删除即可.
那么,这种问题是如何造成的呢?可能就是因为哦们导入三方库的时候,由于功能需求,我们不需要这个三方库,我们移除的时候,在 Library 和 Framework 中并没有移除对应的路径信息,所以就会爆出这样的警告来.这样的警告,我们注意下就可以完全消除了.
前任做的项目中含有友盟SDK(版本:4.2.1),经常会爆出这样的xib警告.
warning: Unsupported Configuration: This file is set to build for a version older than the deployment target. Functionality may be limited.
我们通过错误警告信息找到对应的Xib文件,然后修改** Build for**属性.
我们有时候在Debug模式下没有警告但是在Release模式下出现了如下的警告.
warning:xxxx:No such file or directory
解决方案也是很简单.我们只需要在Project -> targets -> Build Setting -> Debug Information Format把它的值改成DWARF即可.如下图所示.
警告类型
performSelector may cause a leak because its selector is unknown
除了上图的一些警告,我们自己给一个类写Tager-Action的时候,会出现如下警告.
#import <UIKit/UIKit.h>
@interface TapView : UIView
//目标
@property(weak,nonatomic)id target;
//行为
@property(assign,nonatomic)SEL action;
//自定义方法
-(void)addCustomtarget:(id)target andAction:(SEL)action;
@end
#import "TapView.h"
@implementation TapView
//自定义方法
-(void)addCustomtarget:(id)target andAction:(SEL)action{
_action = action;
_target = target;
}
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
//当视图点击的时候,target去执行action的方法并把自己传过去.
//首先代理不能是空,而且代理(代理是对象!)的类中有方法并且能传出过来.
if (nil != _target && [[_target class] instancesRespondToSelector:_action]) {
[_target performSelector:_action withObject:self];
}
}
@end
那么为什么在ARC环境下会造成这种情况呢?这是因为使用 [someController performSelector: NSSelectorFromString(@"someMethod")]; 时ARC并不知道该方法的返回值是什么,不知道该如何处理.所以就会爆这样的错误,那么我们该如何解决呢?我们可以使用上面的预处理指令来屏蔽,不过最好的方法还是从根本上解决这个问题,我们可以使用函数指针的形势来处理这个警告.如下所示.
if (nil != _target && [_target respondsToSelector:_action]) {
NSString *actionName = NSStringFromSelector(_action);
SEL selector = NSSelectorFromString(actionName);
IMP imp = [_target methodForSelector:selector];
void (*func)(id, SEL) = (void *)imp;
func(_target, selector);
}
警告类型
Pointer is missing a nullability type specifier.....
在iOS8.3的写过一个轮播图的三方,这个三方是没有任何警告的,但是在这次使用的时候却在初始化的时候,报了一个警告.如图所示.
其实就是编译器不知道我们这个是不是可为空的,第一个方法那就是我们一个个的修改,比较的繁琐.解决完成之后如下图所示.
第二种就是苹果官方给我们提供的预处理指令,我们只需要把不可为空的属性写在其中即可.
NS_ASSUME_NONNULL_BEGIN
//不可为空的属性
NS_ASSUME_NONNULL_END
示例如下如下所示.
总结
这边文章到这里就结束了,但是我的分享之路还没有结束,接下来,我会把全民星跑项目中的技术点来进行分析共享,也希望大家多多支持我做的骚应用.