谈谈Objective-C的警告 (转)

原文地址:http://onevcat.com/2013/05/talk-about-warning/

一个有节操的程序员会在乎自己的代码的警告,就像在乎饭碗边上有只死蟑螂那样。 ——@onevcat

重视编译警告

现在编译器有时候会很吵,而编译器给出的警告对开发者来说是很有用的信息。警告不会阻止继续编译和链接,也不会导致程序不能运行,但是很多时候编译器会先你一步发现问题所在,对于Objective-C来说特别如此。Clang不仅对于明显的错误能够提出警告(比如某方法或者接口未实现),也能对很多潜在可能的问题做出提示(比如方法已经废弃或者有问题的转换),而这些问题在很多时候都可能成为潜在的致命错误,必须加以重视。

像Ruby或者PHP这样的动态语言没有所谓的编译警告,而C#或者Java这类语言的警告很多都是不得不照顾的废弃方法什么的,很多开发者已经习惯于忽略警告进行开发。OC由于现在由苹果负责维护,Clang的LLVM也同时是苹果在做,可以说从语言到编译器到SDK全局都在掌握之中,因此做OC开发时的警告往往比其他语言的警告更有参考价值。打开尽可能多的警告提示,并且在程序开发中尽量避免生成警告,对于构建一个健壮高效的程序来说,是必须的。

在Xcode中开启额外警告提示

Xcode的工程模板已经为我们设置开启了一些默认和常用的警告提示,这些默认设置为了兼容一些上年头的项目,并没有打开很多,仅是指对最危险和最常见的部分进行了警告。这对于一个新项目来说这是不够用的(至少对我来说是不够用的),在无数前辈大牛的教导下,首先要做的事情就是打开尽可能多的警告提示。

最简单的方法是通过UI来打开警告。在Xcode中,Build Setting选项里为我们预留了一些打开警告的开关,找到并直接勾选相应的选项就可以打开警告。大部分时间里选项本身已经足够能描述警告的作用和产生警告的时机,如果不是很明白的话,在右侧的Quick Help面板里有更详细的说明。对于OC开发来说特有的警告都在Apple LLVM compiler 4.2 - Warnings - Objective C一栏中,不管您是不是决定打开它们,都是值得花时间看一看加以了解的,因为它们都是写OC程序时最应该避免的情况。另外几个Apple LLVM compiler 4.2 - Warnings - …(All languages和C++)也包含了大量的选项,以方便控制警告产生。

当然在UI里一个一个点击激活警告虽然简单,但每次都这样来一回是一种一点也不有趣的做法,特别是在你已经了解它们的内容并决定打开它们的时候。在编译选项中加入合适的flag能够打开或者关闭警告:在Build Setting中的Other C Flags里添加形似-W...的编译标识。你可以在其中填写任意多的-W...以开关某些警告,比如,填写为-Wall -Wno-unused-variable即可打开“全部”警告(其实并不是全部,只是一大部分严重警告而已),但是不启用“未使用变量”的警告。使用-W...的形式,而不是在UI上勾选的一大好处是,在编译器版本更新时,新加入的警告如果包含在-Wall中的话,不需要对工程做任何修改,新的警告即可以生效。这样立即可以察觉到同一个工程由于编译器版本更新时可能带来的隐患。另外一个更重要的原因是..Xcode的UI并没有提供所有的警告 =_=||..

刚才提到的,需要注意的是,-Wall的名字虽然是all,但是这真的只是一个迷惑人的词语,实际上-Wall涵盖的仅只是所有警告中的一个子集。在StackExchange上有一个在Google工作的Clang开发者进行的回答,其中解释了有一些重要的警告组:

  • -Wall 并不是所有警告。这一个警告组开启的是编译器开发者对于“你所写的代码中有问题”这一命题有着很高的自信的那些警告。要是在这一组设定下你的代码出现了警告,那基本上就是你的代码真的存在严重问题了。但是同时,并不是说打开Wall就万事大吉了,因为Wall所针对的仅仅只是经典代码库中的为数不多的问题,因此有一些致命的警告并不能被其捕捉到。但是不论如何,因为Wall的警告提供的都是可信度和优先级很高的警告,所以为所有项目(至少是所有新项目)打开这组警告,应该成为一种良好的习惯。
  • -Wextra 如其所名,-Wextra组提供“额外的”警告。这个组和-Wall组几乎一样有用,但是有些情况下对于代码相对过于严苛。一个很常见的例子是,-Wextra中包含了-Wsign-compare,这个警告标识会开启比较时候对signed和unsigned的类型检查,当比较符两边一边是signed一边是unsigned时,产生警告。其实很多代码并没有特别在意这样的比较,而且绝大多数时候,比较signed和unsigned也是没有太大问题的(当然不排除会有致命错误出现的情况)。需要注意,-Wextra-Wall是相互独立的两个警告组,虽然里面打开的警告标识有个别是重复的,但是两组并没有包含的关系。想要同时使用的话必须在Other C Flags中都加上
  • -Weverything 这个是真正的所有警告。但是一般开发者不会选择使用这个标识,因为它包含了那些还正在开发中的可能尚存bug的警告提示。这个标识一般是编译器开发者用来调试时使用的,如果你想在自己的项目里开启的话,警告一定会爆棚导致你想开始撞墙..

关于某个组开启了哪些警告的说明,在GCC的手册中有一个参考。虽然苹果现在用的都是LLVM了,但是这部分内容应该是继承了GCC的设定。

控制警告,局部加入或关闭

Clang提供了我们自己加入警告或者暂时关闭警告的办法。

强制加入一个警告:

//Generate a warning
#pragma message "Warning 1"

//Another way to generate a warning
#warning "Warning 2"

两种强制警告的方法在视觉效果上结果是一样的,但是警告类型略有不同,一个是-W#pragma-messages,另一个是-W#warnings。对于第二种写法,把warning换成error,可以强制使编译失败。比如在发布一些需要API Key之类的类库时,可以使用这个方法来提示别的开发者别忘了输入必要的信息。

//Generate an error to fail the build.
#error "Something wrong"

对于关闭某个警告,如果需要全局关闭的话,直接在Other C Flags里写-Wno-...就行了,比如-Wextra -Wno-sign-compare就是一个常见的组合。如果相对某几个文件开启或禁用警告,在Build Phases的Compile Source相应的文件中加入对应的编译标识即可。如果只是想在某几行关闭某个警告的话,可以通过临时改变诊断编译标记来抑制指定类型的警告,具体如下:

#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunused-variable"

int a;

#pragma clang diagnostic pop

如果a之后没有被使用,也不会出未使用变量的警告了。对于想要抑制的警告类型的标识名,可以在build产生该警告后的build log中看到。Xcode中的话,快捷键Cmd+7然后点击最近的build log中,进入详细信息中就能看到了。

我应该开启哪些警告提示

个人喜好(代码洁癖)不同,会有不同的需求。我的建议是对于所有项目,特别是新开的项目,首先开启-Wall-Wextra,然后在此基础上构建项目并且避免一切警告。如果在开发过程中遇到了某些确实无法解决或者确信自己的做法是正确的话(其实这种情况,你的做法一般即使不是错误的,也会是不那么正确的),可以有选择性地关闭某些警告。一般来说,关闭的警告项目不应该超过一只手能数出来的数字,否则一定哪儿出问题了..

是否要让警告等于错误

一种很常见的做法和代码洁癖是将警告标识为错误,从而中断编译过程。这让开发者不得不去修复这些警告,从而保持代码干净整洁。在Xcode中,可以通过勾选相应的Treat Warnings as Errors来开启,或者加入-Werror标识。我个人来说不喜欢使用这个设定,因为它总是打断开发流程。很多时候并不可能把代码全写完再编译调试,相反地,我更喜欢写一点就编译运行一下看看结果,这样在中间debug编译的时候会出现警告也不足为奇。另外,如果做TDD开发时,也可能会有大量正常的警告出现,如果有警告就不让编译的话,开发效率可能会打折扣。一个比较好的做法是只在Release Build时将警告视为错误,因为Xcode中是可以为Debug和Release分别指定标识的,所以这很容易做到。

另外也可以只把某些警告当作错误,-Werror=...即可,同样地,也可以在-Werror被激活时使用-Wno-error=...来使某些警告不成为错误。结合使用这些编译标识可以达到很好的控制。

时间: 2024-08-28 13:28:19

谈谈Objective-C的警告 (转)的相关文章

谈谈Objective-C的警告(转载)

一个有节操的程序员会在乎自己的代码的警告,就像在乎饭碗边上有只死蟑螂那样.——@onevcat 重视编译警告 现在编译器有时候会很吵,而编译器给出的警告对开发者来说是很有用的信息.警告不会阻止继续编译和链接,也不会导致程序不能运行,但是很多时候编译器会先你一步发现问题所在,对于Objective-C来说特别如此.Clang不仅对于明显的错误能够提出警告(比如某方法或者接口未实现),也能对很多潜在可能的问题做出提示(比如方法已经废弃或者有问题的转换),而这些问题在很多时候都可能成为潜在的致命错误,

Objective-C

1.Objective-C语言特性 2.static __block const 3.Object-C的内存管理 4.RunLoop 5.iOS消息传递机制 6.iOS程序生命周期 7.MVC设计模式MVVM 8.UIView CALayer Frame 与bounds 9.根类 NSObject 10.多线程简介 11.数据持久化 12.JSON和XML HTML 自定义报文 13.网络编程 HTTP TCP/IP Socket  ASI AFNetwork 14.AppStore上传 及远程

Objective - c Chapter 1 -2 Hello world

Objective - c   Chapter 1  Hello world 1.1 1.2.On the Welcome screen, click "Create a new Xcode project" (see Figure 2-1), or just chooseFile ->New ->New Project. 1.3.在main里写如下代码 #import <Foundation/Foundation.h> int main(int argc, c

谈谈C语言的数据类型

本文摘要: 本文主要讲述C语言中的数据类型,从基本的数据类型到派生的数据类型,从int ,char ,float double ....到指针,数组,函数,指向指针的指针,指向数组的指针,指向函数的指针,指针与数组的区别,指针作为函数参数,函数作为函数参数.作为例子,本文将通过通用链表结构来说明void*如何实现通用结构设计,通过相对通用的哈希结构来说明如何利用函数指针作为函数的参数以及如何在结构体中封装函数指针以实现相当于类的功能结构. 首先,通过一些常见的声明来开始本文,这些声明几乎包含本文

iOS开发核心语言Objective C —— 全部知识点总结

本分享是面向有意向从事iOS开发的伙伴及苹果产品的发烧友,亦或是已经从事了iOS的开发人员,想进一步提升者.假设您对iOS开发有极高的兴趣,能够与我一起探讨iOS开发.一起学习,共同进步.假设您是零基础.建议您先翻阅我之前分享的iOS开发分分钟搞定C语言系列,然后在開始Objective C语言的学习,假设您遇到问题也能够与我探讨.另外将无偿分享自己整理出来的大概400G iOS学习视频及学习资料,都是干货哦.能够新浪微博私信?关注极客James,期待与您的共同学习和探讨! ! 由于时间有限,每

刨根问底Objective-C Runtime

http://chun.tips/blog/2014/11/05/bao-gen-wen-di-objective%5Bnil%5Dc-runtime-(2)%5Bnil%5D-object-and-class-and-meta-class/ 刨根问底Objective-C Runtime(1)- Self & Super 刨根问底Objective-C Runtime(2)- Object & Class & Meta Class 刨根问底Objective-C Runtime(

efffective Objective-C 学习笔记

第一条:了解objective-c语言的起源 消息结构而非函数调用.区别在于:使用消息结构的语言,其运行时所应执行的代码由运行环境来决定:而使用函数调用的语言,则由编译器决定. Objective-c为C语言添加了面向对象特性,是其超集.Objective-C使用动态绑定的消息结构,也就是说,在运行时才会检查对象类型.接受一条消息之后,究竟应执行何种代码,由运行期环境而非编译器来决定.掌握C的内存模型和指针. 第二条:在类的头文件尽量少引入其他头文件 除非确有必要,否则不要引入头文件.一般来说,

Objective—C语言的新魅力——Nullability、泛型集合与类型延拓

Objective-C语言的新魅力 一.引言 在Xcode7中,iOS9的SDK已经全面兼容了Objective-C的一些新特性和新功能.这些功能都只作用于编译期,对程序的运行并没有影响,因此,它可以很好的向下进行兼容,无缝的衔接低版本的iOS系统,那么这些特性有什么样的用处呢,作为开发者,我保证你一定会爱上他们,如果你可以将这些新特性都应用于你的开发,你的开发效率和代码质量,相比之前,会有一个很大的提升. 二.Nullability检测的支持 在swift语言中,通过!和?可以将对象声明成Op

转 谈谈android反编译和防止反编译的方法

谈谈android反编译和防止反编译的方法 android基于java的,而java反编译工具很强悍,所以对正常apk应用程序基本上可以做到100%反编译还原. 因此开发人员如果不准备开源自己的项目就需要知道怎样防止反编译和反编译他人的项目来学习. 2.3版本以上在eclipse自动生成的default.properties文件中加上一句“proguard.config=proguard.cfg”可以对代码进行混淆,反编译后是很难看懂的. 2.3之前的SDK版本也没关系,把上面的proguard