先来看NSObjCRuntime.h
NSObjCRuntime.h
主要是NSInteger封装、指定初始化方法。下面逐句分析认识:
5-6行 #ifndef
#ifndef是"if not defined"的简写。预处理功能中三种(宏定义,文件包含和条件编译)中的第三种——条件编译。防止头文件的重复包含和编译,便于程序的调试和移植。
在C语言中,主要用来避免重复定义错误。在OC语言中,主要用来调试和移植。
假如你有一个C源文件,它包含了多个头文件,比如头文件A和头文件B,而头文件B又包含了头文件A,则最终的效果是,该源文件包含了两次头文件A。如果你在头文件A里定义了结构体或者类类型(这是最常见的情况),那么问题来了,编译时会报大量的重复定义错误。
例如要编写头文件test.h,在头文件开头写上两行:
#ifndef _TEST_H
#define _TEST_H //一般是文件名的大写
头文件结尾写上一行:
#endif
这样一个工程文件里同时包含两个test.h时,就不会出现重定义的错误了。
分析:
当第一次包含test.h时,由于没有定义_TEST_H,条件为真,这样就会包含(执行)#ifndef _TEST_H和#endif之间的代码,当第二次包含test.h时前面一次已经定义了_TEST_H,条件为假,#ifndef _TEST_H和#endif之间的代码也就不会再次被包含,这样就避免了重定义了。
8-9行 #include
从系统目录开始搜索TargetConditionals.h和objc/objc.h文件并把内容代码载入。打开源文件目录,发现系统目录是iPhoneSimulator.sdk ▸ usr ▸ include,刚好也是当前目录。
#include和#import
#import 确定一个文件只能被导入一次,在递归包含或相互包含中不会引起交叉编译,是#include的改良版。
#import和@class
#import 就是把被引用类的头文件走一遍,即把.h文件里的变量和方法包含进来一次,且仅一次,@class只是告诉编译器这是个类,不包含变量和方法,所以后者编译效率更高。
如果你有100个头文件都#import了同一个头文件,或者这些文件是依次引用的,如A–>B, B–>C, C–>D这样的引用关系。当最开始的那个头文件有变化的话,后面所有引用它的类都需要重新编译,如果你的类有很多的话,这将耗费大量的时间。而是用@class则不会。
总结:
- 如果不是c/c++,尽量用#import。
- 能在实现文件中#import,就不在头文件中#import。
- 能在头文件中@class+实现文件中#import,就不在头文件中#import。
11-17行 NSInteger
LP64:是64位环境所使用的不同数据模型中的一,表示采用int32,long64(L),pointer64(P)这种模型的64位机。类似还有ILP64、LLP64。
TARGET_OS_WIN32:Generated code will run under 32-bit Windows
。这里我有个疑惑,代码还能在win32系统上跑?
NS_BUILD_32_LIKE_64:是什么意思,不懂
在苹果的api实现中,NSInteger是一个封装,它会识别当前操作系统的位数,64位返回long,其他返回int。若要考虑兼容,就不要用NSInteger,改用int和long。
19-23行 常量宏定义
宏定义了几个常量NSIntegerMax、NSIntegerMin、NSUIntegerMax、NSINTEGER_DEFINED
25-33行 NS_DESIGNATED_INITIALIZER
如果指定的初始化方法有参,就把他作为默认初始化方法。
涉及两个知识点:NS_DESIGNATED_INITIALIZER和__attribute__
网友评论