#import
我的标头和实现在哪里?
有关于我应该做什么的规则吗?
有没有办法在单个头文件中导入所有内容?
4 回答
鉴于“在大型项目中使用#import 的一般准则。 ”。
嗯,Objective-C 在这方面很像 C 和 C++。将所有#include
s/ #import
s 填充到您的标头中会引入许多不必要的依赖关系,这会为您的构建增加大量时间。因此,还可以在有关 C 和 C++ 依赖项的主题中寻求更多信息。
#import 我的标头和实现在哪里?
通常,您应该#import
只在存在物理依赖的地方编写。由于每个 objc 对象都进行了引用计数,并且您的属性/变量通常不需要存在于标头中,因此#import
s 远低于 C++。
Robin van Dijke 在他的回答 (+1) 中概述了身体依赖的常见情况。
有关于我应该做什么的规则吗?有没有办法在单个头文件中导入所有内容?
好吧,这取决于您的项目的大小。有些人将他们使用的所有框架都添加到 PCH(预编译头文件)中。有些人把最常用的放在 PCH 中,有些人根本不使用 PCH 文件。构建时间越长,项目越复杂,PCH 应该包含的内容就越少。
如果您正在处理“非常大”的项目,您可能不应该在 PCH 中添加更多的 Foundation。
另一个常见的错误是有些人会使用 PCH,因此他们需要输入更少(几乎)。问题在于他们项目的常见包含/标题更改,当发生这种情况时,必须完全重建目标。
此外,如果您可以避免#import
在标头中添加框架/库,则可以节省大量构建时间。
向标头添加#import
s 会导致依赖关系进一步扩散。大量不相关的代码/框架很容易对一些源文件可见,而实际上对大部分源文件可见。
最后,您应该真正尝试将经常更改的标题保留在其他标题之外。
最大的收获是你应该:
- 根据功能分离您的程序
- 赞成前向声明超过
#import
. 编译器必须知道名称,但通常只有在创建/发送对象时才需要导入。 - 尝试将依赖项重的实现保留在
*.m
文件中。
每隔一段时间,它可以帮助检查一些源文件的预处理输出——看看实际#import
编辑了什么——结果可能会非常令人惊讶。
笔记:
- 必须为项目中的每种语言生成 PCH。
- 根据需要编译源代码;例如,如果您有 C 程序,请不要将它们编译为 ObjC。
- 随着项目复杂性的增加,除以目标(例如静态库、模块、逻辑划分测试......)所获得的收益将会增加。以低依赖性正确构建依赖目标本身就是一个很大的话题。如果结构正确,它确实可以帮助您以更高的频率构建和测试(如果您使用持续集成或拥有多个开发人员,这也很重要)。就像头文件依赖一样,如果您从一开始就没有考虑到这一点,那么旧问题可能需要花费大量工时来纠正(在它已经变得难以忍受的缓慢之后)。
可以使用以下约定:
在以下情况下在头文件中使用#import
- 您对导入的类进行子类化 - 您使用来自导入的头文件的协议 - 您使用来自导入的头文件的其他 C 数据结构(枚举、结构)
例子:
#import "SuperClass.h"
#import "Protocol.h"
@class SomeOtherClass
@interface Subclass : SuperClass <Protocol>
SomeOtherClass _instanceVariableToOtherClass
@end
否则@class
在头文件中使用
对于所有其他情况,#import
请在 .m 文件中使用。
注:#import "class.h"
其实是这样的:
#pragma once
#include "class.h"
因此,请注意每个类只导入一次以防止包含循环/循环。
它类似于,#include
语句中的C language
,
基本上#import
声明有两个定义,
1) #import "headerFile.h" // This statement is use for Import any header file in current file (UIController)
2) #import<FramWorkName> // This statement basically use for add any framework in current file (UIController)
要在项目中的任何位置使用任何文件,然后将文件 ( #import "fileName.h"
) 添加到.pch file
. 它是 Prefix 头文件被编译并存储在缓存中,然后在编译期间自动包含在每个文件中。这可以加快编译速度,并允许您包含一个文件,而无需向使用它的每个文件添加导入语句。它们不是必需的,而且每次更改它们时编译速度实际上都很慢。此文件在您的项目中可用.pch file extension
。
像这样:
#ifdef __OBJC__
#import <UIKit/UIKit.h>
#import <Foundation/Foundation.h>
#import "MyFile_Name.h"
您还可以使用PROTOCOL
for 定义要由其他类实现的方法。
只是为了好玩-我将添加一些“基本原则”-尽管没有已经说过的那么详细-有时可以帮助理解整个“过程”。
Implementation.m
文件永远不会(据我所知)#import
'ed - 这就是编译器在“编译”时“正在做”的事情。
您希望所有已编译 ( .m
) 文件“了解”的任何标头都可以放入.pch
文件中。我通常还会将所有类共享的指令(即#import <Cocoa/Cocoa.h>
等)粘贴在其中 - 所以我不必在每个文件中查看它们。
如果您要在头文件中引用以前未声明的类,即AppDelegate.h
@property (nonatomic, strong) HTTPServer *http;
你可以 #import "HTTPServer.h" at the top of that file (or even in the
.pch`)...但通常最好如下引用“转发类”...
@class HTTPServer;
@interface AppDelegate : NSObject ➜ ...
然后#import "HTTPServer.h"
在AppDelegate
's.m
文件中。您需要访问头文件的主要原因......是在您自己的类的“范围”内调用该外部类的实例的方法和使用属性等。这就是为什么你可以简单地在你的标题中“提及”“逃脱” - 你实际上还没有对它做任何事情。@class
唯一需要考虑的另一件事 - 如果您正在构建独立应用程序,这可能不是这种情况 - 但是在构建框架或捆绑包等时......您的类将在“API-kind- of-way”……您可能希望在构建过程中添加一个“复制文件”阶段,这将允许“其他人”通过您的“公共头文件”文件“了解”您的类。在这种情况下......您可以简单地公开一个头文件,该文件导入您的类所需的前向声明,供其他人使用#import
. 这就是您能够访问“伞形框架”中所有类的方式,例如<Foundation/Foundation.h>
使用单个#import
......它在第一个“.h”文件中公开了它“可用”的标题...... á la。 .
#import <Foundation/NSArray.h>
#import <Foundation/NSAutoreleasePool.h>
如果您曾经在 Xcode 之前使用过编译器,那么考虑它的方式是,您需要导入的任何标头都与-I
命令行上的“包含”指令相同。给定一个头文件和一个包含语句src/headers/header.h
的源代码文件..编译命令将是source.c
#include "header.h"
gcc -Iheaders/ source.c -o executable
您可以通过导航到“日志导航器”和 Xcode 并检查所有步骤来了解在 Xcode 中编译某些内容时实际发生的情况。