美文网首页Objective-C 中的代码气味
[译] 为什么 #import 顺序对依赖管理很重要

[译] 为什么 #import 顺序对依赖管理很重要

作者: 韦弦Zhy | 来源:发表于2024-02-28 11:37 被阅读0次

在 Objective-C 中,围绕 #import 顺序存在一些微妙的问题。你可能不相信我,直到你尝试在新项目中重复使用旧代码。

狂野的 #import! 一文中,我们探讨了 #import 指令过多带来的问题。但导入的太少也有可能导致头文件不好,特别是如果你没有注意 .m 文件中的 #import 顺序。

使导入最少化和完整化

在导入时,头文件应满足这两个条件:

  • 应尽量少
  • 应尽量完整

"最少 "仅表示头文件导入的内容不应超过其需要。
"完整 "是指头文件导入编译所需的所有内容。考虑一下:

#import "foo.h"
#import "bar.h"

如果删除 foo.h(或改变顺序)导致 bar.h 无法编译,那么 bar.h 并不完整。

发现不完整的 Header

依赖预编译头文件是导致头文件不完整的一种情况。特别是,预编译的头文件包含某个特定的头文件,并不意味着你可以在其他地方省略它。

另一种头文件不完整的情况是 #import 顺序不当,掩盖了依赖关系。在基于 C 的语言中,程序员在开始编写实现文件时,通常会在最大范围内包含最通用的头文件。然后依次向下,直到包含最具体的头文件:

  • 1、系统头文件
  • 2、其他头文件
  • 3、最后,该文件自身的头文件

这是一种倒退。考虑一下依赖于 <QuartzCore/QuartzCore.h> 的头文件 foo.h。如果 foo.m 首先导入 QuartzCore,然后导入其他内容,最后才导入自己的头文件,那么你可能就不会觉得有必要在 foo.h 中导入 QuartzCore 了。......而下一个程序员如果直接导入 foo.h,就会导致程序崩溃。

原作者在评论答疑中对于此处的解释:
#import is a preprocessor directive. It’s effectively the same as copying and pasting. So if you import QuartzCore first, and your “self” header last, it all expands in your .m before it’s compiled. That’s why the ordering matters.

But if it’s expanded before other headers that use it, those headers will pick it up by accident, not by design. By importing it at the end, any headers that need it but don’t import it themselves will cause a compile-time error. Which is what I want. I want the compiler to tell me about headers that don’t declare their dependencies.

Hopefully this will gradually become history with modules and @import.

#import是一个预处理器指令。它实际上与复制和粘贴相同。因此,如果你先导入 QuartzCore,最后才导入自己头文件,那么在编译之前,所有文件都会在 .m 中展开。这就是为什么顺序很重要。

但是,如果在使用它的其他头文件之前展开它,这些头文件就会意外而非有意地使用它。如果在末尾导入,任何需要它但自己没有导入的头文件都会导致编译时出错。这正是我想要的。我希望编译器能告诉我那些没有声明其依赖关系的头文件。

希望随着模块(modules)和 @import 的使用,这个问题会逐渐成为历史。

好的 #import 顺序

信息披露:以下书籍链接为联盟链接。如果您购买任何商品,我将赚取佣金,您无需支付额外费用。

解决办法很简单:颠倒顺序!从最具体的开始,然后再到最一般的。最重要的是,先包含你自己的头文件。约翰-拉科斯(John Lakos)所著的《大型 C++ 软件设计》是我所知道的唯一一本关于 "物理设计"——如何将源代码编排到文件中的书。

Large-Scale C++ Software Design

该书作者指出:

Latent usage errors can be avoided by ensuring that the .h file of a component parses by itself—without externally-provided declarations or definitions… Including the .h file as the very first line of the .c file ensures that no critical piece of information intrinsic to the physical interface of the component is missing from the .h file (or, if there is, that you will find out about it as soon as you try to compile the .c file).
将 .h 文件作为 .c 文件的第一行,可以确保 .h 文件中不会缺少组件物理接口的关键信息(如果缺少,也不会在编译 .c 文件时发现)。

我是这么做的。如果我在编写 foo.m,我会首先导入 foo.h,并用空行将其与其他导入内容隔开。然后再按顺序导入其他所有导入文件:

#import "foo.h"
#import "abc.h"
#import "def.h"
#import <Abc/Abc.h>

排序可以帮助我找到重复的内容。它还会把角括号导入 <> 放在引号导入之后,这样最一般的标题就会放在最后。

译自:Why #import Order Matters for Dependency Management
侵删

相关文章

  • 通知 传值

    顺序很重要顺序很重要顺序很重要顺序很重要顺序很重要顺序很重要 1.通知的用处就随意多了, 首先他是多对多传值的, ...

  • iOS随笔——编程之美oc代码风格

    头文件#import的顺序 写法模板 #import <系统库> #import <第三方库> #import “...

  • 敏捷--依赖关系管理

    背景 依赖关系管理对于一个项目是否成功交付起着至关重要的作用,本文从业务、组织层面进行分析,如何对强制依赖进行管理...

  • Go语言的依赖管理

    Go语言的依赖管理随着版本的更迭正逐渐完善起来。 依赖管理 为什么需要依赖管理 最早的时候,Go所依赖的所有的第三...

  • 《Shader 入门精要》之透明效果

    为什么透明效果的渲染顺序很重要 书上已经解释的很清楚了,这边说一下,为什么对于循环重叠的半透明物体需要在意渲染顺序...

  • avue【实现增删改查】

    使用方法 先去vue脚手架图形管理里面安装依赖 npm i @smallwei/avue -S import Av...

  • 一步步撸一个app模块化路由、URLscheme访问

    为什么要做路由 是不是非常的乱?相互之间都有依赖,在列表需要import详情页面,详情页面也要import列表,购...

  • 代码规范

    头文件#import的顺序 写法模板import <系统库>import <第三方库>import “其他类”尽量...

  • 数据预处理

    顺序: 导入数据包&数据 import pandas as pd import numpy as np x = ...

  • [Gradle中文教程系列]-跟我学Gradle-5.0:依赖-

    什么是依赖管理 通常而言,依赖管理包括两部分,对依赖的管理以及发布物的管理;依赖是指构建项目所需的构件(jar包等...

网友评论

    本文标题:[译] 为什么 #import 顺序对依赖管理很重要

    本文链接:https://www.haomeiwen.com/subject/sumtzdtx.html