模块化工作中,会指定库与库之间的依赖关系,根据依赖关系分层,但随着开发进行,依赖关系又慢慢被破坏。如何让后续的开发者能够不破坏关系?目前有两种常用手段:
1、不暴露头文件,对于不同的库开发者,其他库以静态库方式。这种方式开发不够方便,容易反复造轮子,对业务分离很清晰的工程可以,但业务相关性较强的就没法这么做了。
2、严格的review机制。耗时耗力。
这两种实施起来都挺不方便,我们的目的是想让没有依赖关系的引用直接import不到头文件,从而提示开发者这个引用非法。
从import入手,先看下import:
import有两种形式,<>和"",他们的区别:
1、stackoverflow上回答较高的解释 the quoted form is for "local" includes of files (you need to specify the relative path from the current file, e.g. #include "headers/my_header.h"), while the angle-bracket form is for "global" includes -- those found somewhere on the include path passed to the compiler。意思就是双引号是用于本地的头文件,需要指定相对路径,尖括号是全局的引用,其路径由编译器提供,如引用系统的库。但在实际工程里,不仅不用指定相对路径,而且用<>也是能引用到的。事出有因,继续看。
2、xcode有个use header map的开关,这个开关的介绍:Enable the use of Header Maps, which provide the compiler with a mapping from textual header names to their locations, bypassing the normal compiler header search path mechanisms. This allows source code to include headers from various locations in the file system without needing to update the header search path build settings。意思是开启这个开关后,在本地会根据当前目录生成一份文件名和相对路径的映射,依靠这个映射,我们可以直接import工程里的文件,不需要依靠header search path。第一点中的问题得到解决,那就直接关闭这个开关吧。
3、如果关闭use header map。那么就涉及到xcode build settings中的header search path 和 user header search path了。
Header Search Paths:
This is a list of paths to folders to be searched by the compiler for included or imported header files when compiling C, Objective-C, C++, or Objective-C++. Paths are delimited by whitespace, so any paths with spaces in them need to be properly quoted.
User Header Search Paths (USER_HEADER_SEARCH_PATHS)
This is a list of paths to folders to be searched by the compiler for included or imported user header files (those headers listed in quotes) when compiling C, Objective-C, C++, or Objective-C++. Paths are delimited by whitespace, so any paths with spaces in them need to be properly quoted. See Always Search User Paths (ALWAYS_SEARCH_USER_PATHS) for more details on how this setting is used. If the compiler doesn't support the concept of user headers, then the search paths are prepended to the any existing header search paths defined in Header Search Paths (HEADER_SEARCH_PATHS).
两者都是提供search path的,区别在于一个指明是用户的。并且提到如果编译器不支持user headers概念,会从header search paths中去寻找。
4、Always Search User Paths (ALWAYS_SEARCH_USER_PATHS)
If enabled, both#include <header.h> -style and#include "header.h" -style directives search the paths in User Header Search Paths (USER_HEADER_SEARCH_PATHS) before Header Search Paths (HEADER_SEARCH_PATHS). As a consequence, user headers, such as your ownString.h
header, have precedence over system headers when using#include <header.h> . This is done using the-iquote
flag for the paths provided inUser Header Search Paths. If disabled and your compiler fully supports separate user paths, user headers are only accessible with#include "header.h" -style preprocessor directives.
在这里我们可以看到,如果打开了Always Search User Paths,<>和""都可以引用到,如果关闭了,user headers 只能通过""引用。
通过这一系列,我们的方案出来了,关闭use header map,关闭Always Search User Paths,通过ruby的xcodeproj 来修改工程文件,根据设定好的依赖关系指定header search path或user header search paths。这样,当不在header search path目录下的文件被import时,编译器是会找不到的。
还有一个和import相关的,在编码过程中,尽量不要在头文件中import另一个头文件,使用前向申明@class。头文件就是一个类的对外接口文件,应该保持干净和尽量只和本类相关。