我正在阅读关于iOS编程的文章,我买了编程iOS 4书。有一个介绍部分,其中提到了几个“文件”。
我不明白源文件是如何组合在一起的。你有一个带有函数声明的头文件,然后你有一个带有函数定义的相应文件。
假设您有Car.h和Car.m& Person.h和Person.m。
现在,如果要在Person类中使用Car,则只导入Car.h文件。这怎么样?我不明白它放在一起的序列并构建一个程序。 (不考虑技术问题,只考虑h / m文件。)
答案 0 :(得分:4)
.h
或“标题文件”包含界面。.m
或“实施文件”包含实施。每个实现文件也称为“编译单元”,因为编译器分别编译每个实现文件。在每个编译单元中,编译器需要知道类型和方法。所有需要知道的关于创建正确代码的类都是关于它实现的方法的信息。
所以让我们假设你有这些文件:
Car.h
#import <Foundation/Foundation.h>
@interface Car : NSObject
- (void)drive;
@end
Car.m
#import "Car.h"
@implementation Car
- (void)drive {
NSLog(@"I'm driving!");
}
@end
Person.h
#import <Foundation/Foundation.h>
@class Car;
@interface Person : NSObject
@property (nonatomic, strong) Car *car;
- (void)start;
@end
Person.m
#import "Person.h"
#import "Car.h"
@implementation Person
@synthesize car;
- (void)start {
[car drive];
}
@end
现在,当编译器开展业务时,它会将Car.m
和Person.m
分别编译为Car.o
和Person.o
。 [然后将这些链接到最终的二进制文件中,但现在这超出了这个问题的范围]。
编译Person.m
时,编译器不需要知道- (void)drive
的{{1}}是如何实现的,但它确实需要知道它存在,它是一种方法不带任何参数并且不返回任何参数。它并不关心实现,只是它存在。因此,您只需要Car
#import
的头文件来告诉编译器Car
上存在的方法。编译器知道实现存在,因为你已经这样说过了,然后链接器就可以正确地将方法调用连接到正确的实现。链接器如何实际执行此操作是一个很大的主题,如果您还不了解它,我建议您单独阅读它。
请注意,对于您使用的所有标准Car
类,例如NS
,NSObject
等,它们都是相同的。您只需要NSString
{{1来自#import
框架,它告诉编译器这些类是什么以及在它们上定义了哪些方法。
答案 1 :(得分:3)
从一组源代码文件创建可执行文件是一个两阶段的过程。
首先,所有.m
文件都是使用Objective-C编译器单独编译的。这会将每个文件转换为.o
文件,这是一个目标代码文件。但是,如果.m
文件中的代码引用其他.m
文件中定义的内容,则编译器不会知道这些内容,因此它只会在.o文件中留下未解析的引用。
第二阶段称为链接。这将获取所有.o
个文件并将它们组合成可执行文件。当链接器在一个.o
文件中找到未解析的引用时,它会检查所有其他文件以解析引用。
头文件允许编译器从当前正在编译的特定.m
文件之外获取一些信息。因此,如果您有两个类Foo
和Bar
,它们通常在文件Foo.m
和Bar.m
中定义,以便编译器知道类Bar
看起来像什么在编译Foo.m
时,我们将类Bar
的接口声明放在头文件中(通常为Bar.h
)并将其导入.m
文件。如果你看到
#import "Bar.h"
从字面上看,编译器在编译之前已将整个头文件复制粘贴到源代码文件中。
答案 2 :(得分:1)
到目前为止,您使用的语言是什么?许多语言都是这样做的,包括c和c ++。 m文件被编译成实际程序,h文件提供了与之交互的方法列表。虽然如果您与目标c运行时交互仍然可以调用方法,但编译器不会保证它们的存在,除非它们在h文件中。
现在,我说保证,但如果你不提供m文件中的实现,编译器的兄弟,链接器将适合。它将尝试基于其h文件跳转到另一个m文件,但只是悲惨地发现它不在那里。
像这样分割的好处是你可以将你的源代码编译成一个库并与h文件一起分发,而另一个应用程序可以使用它而不需要实现源代码。
总之,m文件编译成丢失的位岛,而h文件是绕过它的地图。如果地图上的某些内容不存在,那么您将迷路。如果某些东西存在但不在地图上,那么你将很难找到它。
答案 3 :(得分:0)
头文件指定可以将哪些消息(其他语言中的“方法”)传递给类。这是编译器编译代码时需要知道的所有内容;链接器最终将使用*.m
文件连接所有内容。
答案 4 :(得分:0)
编译器会为您处理。
正如您所说,头文件只包含声明。 它就像是实际代码的接口,这是编译器获取其余代码时唯一需要知道的东西。