我正在使用一些新的 iOS 7 功能并使用 WWDC 视频“在 iOS 上实现 Engaging UI”中讨论的一些图像效果。为了在会话的源代码中产生模糊效果,UIImage
通过导入 UIKit 的类别进行了扩展,如下所示:
@import UIKit;
我想我在另一个会话视频中看到了一些关于此的内容,但我找不到它。我正在寻找有关何时使用它的任何背景信息。它只能与 Apple 框架一起使用吗?使用这个编译器指令的好处是否足以让我回去更新旧代码?
我正在使用一些新的 iOS 7 功能并使用 WWDC 视频“在 iOS 上实现 Engaging UI”中讨论的一些图像效果。为了在会话的源代码中产生模糊效果,UIImage
通过导入 UIKit 的类别进行了扩展,如下所示:
@import UIKit;
我想我在另一个会话视频中看到了一些关于此的内容,但我找不到它。我正在寻找有关何时使用它的任何背景信息。它只能与 Apple 框架一起使用吗?使用这个编译器指令的好处是否足以让我回去更新旧代码?
这是一个称为模块或“语义导入”的新功能。有关 Session 205和404的WWDC 2013视频中有更多信息。这是预编译头文件的一种更好的实现。您可以将模块与 iOS 7 和 Mavericks 中的任何系统框架一起使用。模块是框架可执行文件及其头文件的封装,被吹捧为比.#import
使用的一大优点@import
是你不需要在项目设置中添加框架,它是自动完成的。这意味着您可以跳过单击加号按钮并搜索框架(金色工具箱)的步骤,然后将其移至“框架”组。它将许多开发人员从神秘的“链接器错误”消息中解救出来。
您实际上不需要使用@import
关键字。如果您选择使用模块,所有#import
和#include
指令都将被映射为@import
自动使用。这意味着您不必更改源代码(或从其他地方下载的库的源代码)。据说使用模块也可以提高构建性能,特别是如果您没有很好地使用 PCH 或者您的项目有很多小源文件。
模块是为大多数 Apple 框架(UIKit、MapKit、GameKit 等)预先构建的。您可以将它们与您自己创建的框架一起使用:如果您在 Xcode 中创建 Swift 框架,它们会自动创建,您可以为任何 Apple 或 3rd-party library自己手动创建一个“.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 中的子模块会自动完成。
Nice answer you can find in book Learning Cocoa with Objective-C (ISBN: 978-1-491-90139-7)
Modules are a new means of including and linking files and libraries into your projects. To understand how modules work and what benefits they have, it is important to look back into the history of Objective-C and the #import statement Whenever you want to include a file for use, you will generally have some code that looks like this:
#import "someFile.h"
Or in the case of frameworks:
#import <SomeLibrary/SomeFile.h>
Because Objective-C is a superset of the C programming language, the #import state‐ ment is a minor refinement upon C’s #include
statement. The #include statement is very simple; it copies everything it finds in the included file into your code during compilation. This can sometimes cause significant problems. For example, imagine you have two header files: SomeFileA.h
and SomeFileB.h
; SomeFileA.h
includes SomeFileB.h
, and SomeFileB.h
includes SomeFileA.h
. This creates a loop, and can confuse the coimpiler. To deal with this, C programmers have to write guards against this type of event from occurring.
When using #import
, you don’t need to worry about this issue or write header guards to avoid it. However, #import
is still just a glorified copy-and-paste action, causing slow compilation time among a host of other smaller but still very dangerous issues (such as an included file overriding something you have declared elsewhere in your own code.)
Modules are an attempt to get around this. They are no longer a copy-and-paste into source code, but a serialised representation of the included files that can be imported into your source code only when and where they’re needed. By using modules, code will generally compile faster, and be safer than using either #include or #import
.
Returning to the previous example of importing a framework:
#import <SomeLibrary/SomeFile.h>
To import this library as a module, the code would be changed to:
@import SomeLibrary;
This has the added bonus of Xcode linking the SomeLibrary framework into the project automatically. Modules also allow you to only include the components you really need into your project. For example, if you want to use the AwesomeObject component in the AwesomeLibrary framework, normally you would have to import everything just to use the one piece. However, using modules, you can just import the specific object you want to use:
@import AwesomeLibrary.AwesomeObject;
For all new projects made in Xcode 5, modules are enabled by default. If you want to use modules in older projects (and you really should) they will have to be enabled in the project’s build settings. Once you do that, you can use both #import
and @import
statements in your code together without any concern.
它目前仅适用于内置系统框架。如果您#import
像苹果一样使用仍然 UIKit
在应用程序委托中导入框架,它将被替换(如果模块已打开并且被识别为系统框架)并且编译器会将其重新映射为模块导入而不是头文件的导入. 因此,在可能的情况下,保留它与#import
将其转换为模块导入一样
@import Module(ObjC) 或语义导入
历史:
#include => #import => Precompiled Headers .pch => @import Module(ObjC); => import Module(Swift)
[#include vs #import]
[预编译头文件 .pch]
@import <module_name>;
声明告诉编译器加载(而不是编译)模块的预编译二进制文件,这减少了构建时间。以前编译器每次运行时都会编译依赖项,但现在应该预先编译并加载
//previously
run into dependency -> compile dependency
run into dependency -> compile dependency
//@import
compile dependency
run into dependency -> load compiled binary
run into dependency -> load compiled binary
[Modulemap] - 模块和标头之间的桥梁
Xcode
Enable Modules(C and Objective-C)(CLANG_ENABLE_MODULES)
- CLANG#include, #import
指令会自动转换为@import
带来所有优势。Modulemap
允许无缝执行,因为包含标题和子/模块之间的映射
经过-fmodules
#include, #import -> @import
Link Frameworks Automatically(CLANG_MODULES_AUTOLINK)
- 启用系统模块自动链接。需要激活CLANG_ENABLE_MODULES
。自动链接允许-framework <framework_name>
基于#import, @import(Objective-C), import(Swift)
如果否 - 通过-fno-autolink
标志
如果您想#import <UIKit/UIKit.h>
手动处理 system() 链接(而不是自动链接),您有两种变体:
将依赖添加到General -> Frameworks and Libraries or Frameworks, Libraries, and Embedded Content
Build Settings -> Other Linker Flags(OTHER_LDFLAGS) -> -framework <module_name>
在以下情况下引发下一个错误:
CLANG_ENABLE_MODULES
被禁用CLANG_MODULES_AUTOLINK
被禁用并且没有手动链接Undefined symbol: _OBJC_CLASS_$_UIView
Undefined symbols for architecture x86_64:
"_OBJC_CLASS_$_UIView", referenced from:
objc-class-ref in ClassB.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1
逆向工程
otool -l <binary>
//-l print the load commands
//find LC_LINKER_OPTION
//cmd LC_LINKER_OPTION
似乎自从 XCode 7.x 启用 clang 模块时会出现很多警告CLANG_ENABLE_MODULES
使用模块有一些好处。除非创建了模块映射,否则您只能将它与 Apple 的框架一起使用。@import
添加到文件时有点类似于预编译头文件,.pch
这是一种调整应用程序编译过程的方法。此外,您不必以旧方式添加库,@import
实际上使用起来更快更高效。如果您仍在寻找不错的参考资料,我强烈建议您阅读这篇文章。