#pragma介绍

#pragma是一个预处理指令,pragma的中文意思是『编译指示』。它不是Objective-C中独有的东西(貌似在C/C++中使用比较多),最开始的设计初衷是为了保证代码在不同编译器之间的兼容性,但随着时间推移,它出现在了更多更丰富的应用场景中。

#pragma代码是在编译期间处理的;它既不属于注释,也不属于逻辑代码的一部分;并且它和其他预处理命令譬如#ifdef ... #endif不同,它不会影响代码在运行时的逻辑处理,所以#pragma指令丝毫不会影响到程序在运行时的性能。根据Mattt Thompson大神的描述,在当前Xcode开发环境中,#pragma主要有两个应用场景:组织代码和屏蔽编译警告。

#pragma mark组织代码

组织代码是个人卫生问题,个人卫生不好(代码组织不好)不能反映人品(技术能力),但它在某种程度中影响了别人是否愿意和他搞基(合作)。在一个项目(尤其是多人合作的项目)中,应该有一个比较好的内部一致性编码习惯,不好的习惯或者缺乏一致性,会使得项目难以维持,协作也不便(这点笔者深有体会,笔者目前的项目有一个同事,编码能力尚可,但编码习惯实在太糟糕,代码紧凑,从来不空格,更妄谈空行和注释了,甚至经常不对齐,看他的代码,一点修改的欲望都没有,想的只是自己重写一遍=_=)。

在组织代码时充分使用#pragma mark就是写出『干净代码』的一个重要环节,就像这样:

#pragma mark - UIViewController

- (void)viewDidLoad {

[super viewDidLoad];
} - (void)dealloc { } #pragma mark - IBAction - (IBAction)loginNow:(id)sender { } #pragma mark - UITableViewDataSource - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return ;
} #pragma mark - UITableViewDelegate - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { }

上述代码中使用#pragma mark将@implementation中的代码(方法)分成了几个逻辑section,这种处理并没有改变程序逻辑,但我们在使用Xcode代码导航工具时可以在视觉上汲取片刻的欢愉:

组织N个方法为一个section的依据是什么呢?这个就见仁见智了。一般来说:

  • 将一个protocol的方法组织成一个section;
  • 将target-action类型方法组织成一个section;
  • 将notification相关方法组织成一个section;
  • 将需要override的父类方法组成成一个section;

#pragma屏蔽编译警告

使用#pragma mark来组织代码使用比较普遍,相对而言,使用#pragma指令屏蔽编译器和静态分析器的警告相对来说就比较新鲜了。

You know what is even more annoying than poorly-formatted code? Code that generates warnings. 编译警告很可恶,应该尽可能修改代码干掉这些警告,但是有些时候有些警告无法避免,譬如我们在编写@selector(aMethodName)这样的代码时,如果aMethodName没有在上下文中出现,可能会出现含有『undeclared-selector』关键词的warning,有洁癖的程序员会想到干掉这个warning,此时#pragma指令就派上用场了。譬如:

#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wundeclared-selector"
if ([self.selectedViewController respondsToSelector:@selector(isReadyForEditing)]) {
boolNumber = [self.selectedViewController performSelector:@selector(isReadyForEditing)];
}
#pragma clang diagnostic pop

这是Clang编译器提供的一种解决方案,通过使用#pragma clang diagnostic push/pop来告诉编译器仅仅为某一特定部分代码(记得要在代码片段末尾使用pop将最初的diagnostic设置恢复哦)忽视特定警告。

上述示例中#pragma clang diagnostic ignored后面的"-Wundeclared-selector"指示的是『特定警告』,再别的应用场景中肿么知道该填写什么呢?网络是强大的,有一个(可能是N个)愤怒的网友对clang警告消息做了一个总结,之所以说这个网友“愤怒”,是因为其链接非常有意思:http://fuckingclangwarnings.com/

Finally, you can read more about the LLVM’s use of #pragma in the Clang Compiler User’s Manual.

最后,感谢大神Mattt Thompson,本文的参考资料完全来自于《#pragma》,本来想用自己的语言完成这篇博客,边读边写,最后发现几乎差不多了,没留下啥自己的东西,就这样吧!

参考资料

  1. #pragma》;
  2. clang diagnostics》;

预处理指令#pragram的更多相关文章

  1. 预处理指令#pragma

    #pragma介绍 #pragma是一个预处理指令,pragma的中文意思是『编译指示』.它不是Objective-C中独有的东西(貌似在C/C++中使用比较多),最开始的设计初衷是为了保证代码在不同 ...

  2. C/C++预处理指令#define,#ifdef,#ifndef,#endif…

    2016年12月29日更新: 今天查看以前文件的时候, 突然发现了#error 这个预处理指令.然后回想一下工作, 发现这个指令使用场景还是很多的.比如: 一个项目的模块儿之多,源文件之大,代码之多, ...

  3. Effective Objective-C 2.0 — 第四条:多用类型常量,少用#define预处理指令

    第四条:多用类型常量,少用#define预处理指令 使用#define 预处理的坏处:定义出来的常量没有类型信息,编译器只是会在编译前据此执行查找与替换操作.即使有人重新定义了常量值,编译器也不会产生 ...

  4. VC中预处理指令与宏定义详解

    刚接触到MFC编程的人往往会被MFC 向导生成的各种宏定义和预处理指令所吓倒,但是预处理和宏定义又是C语言的一个强大工具.使用它们可以进行简单的源代码控制,版本控制,预警或者完成一些特殊的功能. 一个 ...

  5. C#中的预处理指令

    C#中的预处理指令 作为预处理中的一对:#region name ,#endregion可能是大家使用得最多的,我也常用它来进行代码分块,在一个比较长的cs文件中,这么做确实是一件可以让你使代码更清晰 ...

  6. C#学习笔记(十五):预处理指令

    C#和C/C++一样,也支持预处理指令,下面我们来看看C#中的预处理指令. #region 代码折叠功能,配合#endregion使用,如下: 点击后如下: 条件预处理 条件预处理可以根据给出的条件决 ...

  7. iOS预处理指令

    预处理过程扫描源代码,对其进行初步的转换,产生新的源代码提供给编译器.可见预处理过程先于编译器对源代码进行处理. 预处理指令是以#开头的代码行,#后是指令关键字,在关键字和#号之间允许存在任意个数的空 ...

  8. #pragma预处理指令讲解

    在所有的预处理指令中,#Pragma 指令可能是最复杂的了,它的作用是设定编译器的状态或者是指示编译器完成一些特定的动作.#pragma指令对每个编译器给出了一个方法,在保持与C和C++语言完全兼容的 ...

  9. C# 预处理指令

    导读 1.什么是预处理 2.预处理的好处 3.C#中的常见预处理指令 4.总结 什么是预处理         在计算机科学中,预处理通常是指利用某一程序(通常是预处理器)对某一格式的源码(如.cs C ...

随机推荐

  1. 一起来学Spring Cloud | 第五章:熔断器 ( Hystrix)

    在微服务项目中,一个系统可以分割成很多个不同的服务模块,不同模块之间我们通常需要进行相互调用.springcloud中可以使用RestTemplate+Ribbon和Feign来调用(工作中基本都是使 ...

  2. log4j配置(转载)

    Log4J的配置文件(Configuration File)就是用来设置记录器的级别.存放器和布局的,它可接key=value格式的设置或xml格式的设置信息.通过配置,可以创建出Log4J的运行环境 ...

  3. centos6安装概述

    1.1.选择安装类型:[Install or upgrade an existing system]安装或升级现有系统 1.2.介质校验:[Skip]跳过介质校验,校验时间较长 1.3.语言选择:[E ...

  4. HDFS api操作

    import java.net.URI;import java.util.Iterator;import java.util.Map.Entry; import org.apache.hadoop.c ...

  5. VC++下编译Libgeotiff(含Libtiff)

    转自原文Win10+VC++下编译Libgeotiff(含Libtiff)详细图文教程 GeoTiff是包含地理信息的一种Tiff格式的文件.Libgeotiff就是一个操作GeoTiff文件的库.同 ...

  6. hdu 1689 Alien’s Necklace (bfs层次图剪枝)

    Alien's Necklace Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others ...

  7. time is always a factor, time is always now!!!!

    https://www.linkedin.com/pulse/time-always-now-joe-alderman ---------------------------------------- ...

  8. CF 558B(Amr and The Large Array-计数)

    B. Amr and The Large Array time limit per test 1 second memory limit per test 256 megabytes input st ...

  9. ZOJ ACM 1314(JAVA)

    昨天做了几个题目.过于简单,就不在博客里面写了. 1314这道题也比較简单,写出来是由于我认为在这里有一个小技巧,对于时间复杂度和空间复杂度都比較节省. 这个题目类似哈希表的求解.可是更简单.刚拿到题 ...

  10. Linux/UNIX之文件和文件夹(2)

    文件和文件夹(2) link.ulink.remove和rename函数 #include <unistd.h> int link(const char *oldpath, const c ...