@import vs #import-iOS 7


432

我正在玩一些新的iOS 7功能,并使用WWDC视频“在iOS上实现Engaging UI”中讨论的一些Image Effects。为了在会话的源代码中产生模糊效果,UIImage通过导入UIKit的类别进行了扩展,如下所示:

@import UIKit;

我想我在另一个会话视频中看到了有关此内容的信息,但是我很难找到它。我正在寻找有关何时使用它的任何背景信息。只能与Apple框架一起使用吗?使用此编译器指令的好处是否足以使我返回并更新旧代码?


Answers:


838

这是一个称为模块或“语义导入” 的新功能。WWDC 2013视频中有关于Session 205404的更多信息。这是对预编译标头的更好实现。您可以将模块与iOS 7和Mavericks中的任何系统框架一起使用。模块是框架可执行文件及其标头的封装,并且被吹捧为比更加安全,高效#import

使用的最大优点之一@import是,您无需在项目设置中添加框架,而是自动完成的。这意味着您可以跳过单击加号按钮并搜索框架(黄金工具箱)的步骤,然后将其移至“框架”组。它将使许多开发人员免受神秘的“链接器错误”消息的影响。

您实际上不需要使用@import关键字。如果您选择使用模块,则all #import#include指令都将映射为@import自动使用。这意味着您不必更改源代码(或从其他位置下载的库的源代码)。据说使用模块也可以提高构建性能,尤其是在您没有很好地使用PCH或项目中有许多小源文件的情况下。

模块是为大多数Apple框架(UIKit,MapKit,GameKit等)预先构建的。您可以将它们与自己创建的框架一起使用:如果您在Xcode中创建Swift框架,则会自动创建它们,并且您可以自己为任何Apple或3rd-party库手动创建“ .modulemap”文件。

您可以使用代码完成来查看可用框架的列表:

在此处输入图片说明

默认情况下,在Xcode 5的新项目中启用了模块。要在较旧的项目中启用它们,请进入项目构建设置,搜索“模块”,然后将“启用模块”设置为“是”。“链接框架”也应为“是”:

您必须使用Xcode 5和iOS 7或Mavericks SDK,但仍可以发布用于较旧的操作系统(例如iOS 4.3或其他版本)。模块不会改变代码或任何源代码的构建方式。


从WWDC幻灯片中:

  • 导入框架的完整语义描述
  • 不需要解析头
  • 导入框架接口的更好方法
  • 加载二进制表示
  • 比预编译头更灵活
  • 不受本地宏定义的影响(例如#define readonly 0x01
  • 默认情况下为新项目启用

要显式使用模块:

替换#import <Cocoa/Cocoa.h>@import Cocoa;

您也可以仅使用以下符号导入一个标头:

@import iAd.ADBannerView;

子模块会在Xcode中为您自动完成。


15
@DaveDeLong&Klaas:谢谢!我必须承认,当我第一次回答这个问题时,我对模块一无所知。我去看了Session 404来学习它。Doug Gregor(LLVM专家)所做的演示确实做得很好。还有一个C ++模块讨论,在这里解释了优点:youtube.com/watch?
v=4Xo9iH5VLQ0

3
@nevan-感谢您的回答。我只是想补充一下,这些模块目前尚不支持3rd Party和您自己的框架。
jamdaddy25年

您可以将其用于自己的课程吗?
cfischer 2013年

5
我认为,如果提供了适当的module.map,则您应该能够@import 3rd party框架。LLVM clang模块文档:clang.llvm.org/docs/Modules.html#module-map-language
bames53 2013年

1
哦,实际上这@import sqlite3对我来说似乎有用,因为我为它创建了自己的module.map,当我意识到sqlite包含在OS X中并删除了我的module.map时,编译器继续使用旧模块。
bames53 2013年

46

您可以在《用Objective-C学习可可》(ISBN:978-1-491-90139-7)一书中找到不错的答案

模块是一种将文件和库包含并链接到项目中的新方法。要了解模块如何工作以及它们有什么好处,回顾一下Objective-C和#import语句的历史很重要,只要想包含一个文件供使用,通常就会有一些类似以下的代码:

#import "someFile.h"

或就框架而言:

#import <SomeLibrary/SomeFile.h>

因为Objective-C是C编程语言的超集,所以#import #include声明是对C 语句的较小改进。#include语句非常简单;它将在编译过程中将在包含的文件中找到的所有内容复制到您的代码中。有时这可能会导致严重的问题。例如,假设您有两个头文件:SomeFileA.hSomeFileB.h; SomeFileA.h包括SomeFileB.h,并且SomeFileB.h包括SomeFileA.h。这将创建一个循环,并可能使coimpiler混淆。为了解决这个问题,C程序员必须编写防范此类事件发生的措施。

使用时#import,您无需担心此问题,也不必编写标题保护程序来避免此问题。但是,#import这仍然只是美化的复制和粘贴操作,从而在许多其他较小但仍然非常危险的问题之间引起了缓慢的编译时间(例如,包含的文件将覆盖您在自己的代码中其他地方声明的内容)。

模块是一种尝试来解决这个问题。它们不再是对源代码的复制粘贴,而是对包含文件的序列化表示,仅当需要它们时,才可以将其导入源代码。通过使用模块,代码通常比使用#include或#include更快,并且更安全#import

回到前面的导入框架示例:

#import <SomeLibrary/SomeFile.h>

要将这个库作为模块导入,代码将更改为:

@import SomeLibrary;

这具有Xcode自动将SomeLibrary框架链接到项目中的额外好处。模块还允许您仅将真正需要的组件包含到项目中。例如,如果要在AwesomeLibrary框架中使用AwesomeObject组件,通常只需要导入所有内容即可使用一个。但是,使用模块,您可以仅导入要使用的特定对象:

@import AwesomeLibrary.AwesomeObject;

对于使用Xcode 5创建的所有新项目,默认情况下启用模块。如果您想在较旧的项目中使用模块(确实应该),则必须在项目的构建设置中将其启用。一旦这样做,就可以在代码中一起使用#import@import语句,而无需担心。


我在Xcode 4上首次启动的项目(Xcode 6)中没有启用模块的选项。我可以手动添加吗?
Awesome-o

构建目标是iOS 6,我认为这就是问题所在
Awesome-o

4

当前仅适用于内置系统框架。如果您#import仍然像苹果一样使用,仍会UIKit在应用程序委托中导入 框架,则将其替换(如果模块已打开且其被识别为系统框架),并且编译器会将其重新映射为模块导入,而不是头文件的导入。所以#import无论如何都将与将其转换为模块导入相同



1

使用模块有一些好处。除非创建了模块映射,否则您只能在Apple的框架中使用它。@import与添加到.pch文件中的预编译头文件有点类似,这是调整应用程序编译过程的一种方式。另外,您不必以旧的方式添加库@import,实际上使用起来更加快捷高效。如果您仍在寻找不错的参考,我强烈建议您阅读本文


0

历史:

#include => #import => .pch => @import

#include vs #import
.pch-预编译头

模块- @import

Product Name == Product Module Name 

@module声明告诉编译器加载框架的预编译二进制文件,这样可以减少构建时间。模块化框架包含.modulemap[关于]

如果在Xcode项目中启用了模块功能,#include并且#import指令自动转换为@import带来所有优势,

在此处输入图片说明

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.