谈谈Objective-C的警告

一个有节操的程序员会在乎自己的代码的警告,就像在乎饭碗边上有只死蟑螂那样。 ——@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=...来使某些警告不成为错误。结合使用这些编译标识可以达到很好的控制。

转载自:https://onevcat.com/

时间: 2024-11-08 22:30:16

谈谈Objective-C的警告的相关文章

objective c-ios项目中隐藏警告

问题描述 ios项目中隐藏警告 项目中: Assigning to 'AppDelegate *' from incompatible type 'id'. 这个警告应该怎么解决额? 在.m中声明: AppDelegate *appdev; 在viewDidLoad中 { appdev = [[UIApplication sharedApplication]delegate]; <= warning here} 我想隐藏这个警告,可以么? 解决方案 需要隐式指明类型,改成 appdev =(Ap

如何关闭和重启您的Linux系统,警告用户系统即将关闭

在本文中,将了解如何关闭和重启您的 Linux 系统,警告用户系统即将关闭,并切换到单用户模式或限制性更大或更小的运行级别.您将学习: 设置默认运行级别 更改运行级别 更改为单用户模式 从 命令行关闭或重启系统 就主要的系统事件向用户发出警告,这些事件中包括切换到另一个运行级别 正确终止流程 除非另有说明,否则本文中的示例使用的都是配备了 2.6.26 内核的 Fedora 8 系统.upstart 示例使用的是配备了 2.6.34 内核的 Fedora 13,或配备了 2.6.35 内核的 h

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

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

谈谈和前老板“周鸿祎”的接触和印象

不知道是不是因为前老板"周鸿祎"最近才出了新书,突然让我回想起在360工作的那2年的点点滴滴,想起了前老板"周鸿祎". 在外面参加行业聚会,只要跟别人说起我在360工作过,常有人问我对老周是什么的印象.可能别的互联网巨头对我来说都比较遥远,从内心里我对"周鸿祎"是非常敬佩的,做事有魄力,敢想敢做.记得才到360工作的时候,在我和同事的眼里,搜狐,网易,新浪就是互联网里的大公司(那时候我还不懂是什么是BAT,一直觉得新浪,搜狐就是第一阵营的),但现

从美橙互联K站事件——谈谈DNS和国内IDC

中介交易 SEO诊断 淘宝客 云主机 技术大厅 近日,从QQ群.微博等渠道看到有人在谈"使用美橙互联虚拟主机网站被K"."网站在美橙互联大面积出现收录下降"."美橙互联DNS屏蔽百度蜘蛛抓取"等问题.谈论者从"受害者"到煽风点火的"卖主机"的."卖DNS"的,好不热闹.正好前段时间笨鸟对在美橙放的网站做了监控,就也来谈谈"美橙互联K站门". 一.美橙K站门事件经过 最

戴仁光:社区如何运营 谈谈个人的一点想法

中介交易 http://www.aliyun.com/zixun/aggregation/6858.html">SEO诊断 淘宝客 云主机 技术大厅 很多站长的做站第一步就是论坛,而我的第一步是简简单单的文章站,而且一直利用的就是SEO获取流量,然后赚取广告费,曾经大学里弄过一个论坛,但是感觉自己什么都不会,人气没有不说,管理方面也出现了很多的问题.之后在阿里妈妈社区做了版主,就放弃了自己社区没再做了,但是通过阿里妈妈社区的学习,我觉得自己确实获得了很多成长了很多.现在的超级站长社区的运营

谈谈地方人才网站如何打造属于站点的特色“窗口”

中介交易 http://www.aliyun.com/zixun/aggregation/6858.html">SEO诊断 淘宝客 云主机 技术大厅 一座城市的窗口能够展现自身形象,一个单位的窗口能够体现单位的优质服务,那么一个站点如果拥有自身特色的窗口又能够做什么呢?笔者在10年就建立了一个西安人才网站,网站运营到现在已经形成了以"免费"为基础的特色窗口,通过免费窗口的树立网站到现在已经形成了一定的规模,很多站长就要问我是如何打造自己的特色窗口的呢?下面笔者来详细谈谈

ios-在上传苹果应用时出现警告

问题描述 在上传苹果应用时出现警告 应用上传到应用商店时,出现这样的警告: The app references non-public selectors in ""App Name"" instance viewController 不知道怎么消除这个警告? 应用可以通过吗? 解决方案 我的应用中有non-public部分也通过了,不过可以用App Scanner帮你找出应用中的问题,哪里是non-public

警告-Type safety: Unchecked cast from Object to List&amp;amp;lt;Blog&amp;amp;gt; 大家讨论一下!

问题描述 Type safety: Unchecked cast from Object to List<Blog> 大家讨论一下! 先看这个警告出现的代码吧: Message message = new Message(); message.obj = bos; handler.sendMessage(message);` 这是在一个线程里发送信息到主线程.下面在主线程进行强转: mList.addAll((List) msg.obj); 这样转的时候会出现上面的警告,在网上找到了几个方法方