我正在使用一些新的 iOS 7 功能并使用 WWDC 视频“在 iOS 上实现 Engaging UI”中讨论的一些图像效果。为了在会话的源代码中产生模糊效果,UIImage
通过导入 UIKit 的类别进行了扩展,如下所示:
@import UIKit;
我想我在另一个会话视频中看到了一些关于此的内容,但我找不到它。我正在寻找有关何时使用它的任何背景信息。它只能与 Apple 框架一起使用吗?使用这个编译器指令的好处是否足以让我回去更新旧代码?
.mm
个文件,或者更确切地说是 Objective-C++
,@import
是 not supported yet(我对 g++
和 clang++
都进行了测试,因为我真的很想完成这项工作)。
这是一个名为Modules 或“语义导入”的新功能。会议 205 和 404 的 WWDC 2013 视频中有更多信息。这是预编译头文件的一种更好的实现。 您可以将模块与 iOS 7 和 Mavericks 中的任何系统框架一起使用。模块是框架可执行文件及其标头的打包,被吹捧为比 #import
更安全、更高效。
使用 @import
的一大优势是您无需在项目设置中添加框架,它会自动完成。这意味着您可以跳过单击加号按钮并搜索框架(金色工具箱)的步骤,然后将其移至“框架”组。它将许多开发人员从神秘的“链接器错误”消息中解救出来。
您实际上不需要使用 @import
关键字。如果您选择使用模块,所有 #import
和 #include
指令都会自动映射为使用 @import
。这意味着您不必更改源代码(或从其他地方下载的库的源代码)。据说使用模块也可以提高构建性能,特别是如果您没有很好地使用 PCH 或者您的项目有很多小源文件。
模块是为大多数 Apple 框架(UIKit、MapKit、GameKit 等)预先构建的。您可以将它们与您自己创建的框架一起使用:如果您在 Xcode 中创建一个 Swift 框架,它们会自动创建,您可以为 any Apple or 3rd-party library 自己手动创建一个“.modulemap”文件。
您可以使用代码完成来查看可用框架的列表:
https://i.stack.imgur.com/h7UNV.png
Xcode 5 的新项目中默认启用模块。要在旧项目中启用它们,请进入项目构建设置,搜索“模块”并将“启用模块”设置为“是”。 “链接框架”也应该是“是”:
https://i.stack.imgur.com/723Su.png
您必须使用 Xcode 5 和 iOS 7 或 Mavericks SDK,但您仍然可以为较旧的操作系统(比如 iOS 4.3 或其他)发布。模块不会更改您的代码的构建方式或任何源代码。
来自 WWDC 幻灯片:
导入框架的完整语义描述 不需要解析头文件 导入框架接口的更好方法 加载二进制表示 比预编译头文件更灵活 不受本地宏定义的影响(例如 #define readonly 0x01) 默认为新项目启用
要显式使用模块:
将 #import <Cocoa/Cocoa.h>
替换为 @import Cocoa;
您也可以使用此表示法仅导入一个标头:
@import iAd.ADBannerView;
Xcode 中的子模块会自动完成。
很好的答案可以在《Learning Cocoa with Objective-C》一书中找到(ISBN:978-1-491-90139-7)
模块是一种将文件和库包含和链接到项目中的新方法。要了解模块是如何工作的以及它们有什么好处,回顾一下 Objective-C 的历史和#import 语句是很重要的。当你想要包含一个文件以供使用时,你通常会有一些看起来像这样的代码:
#import "someFile.h"
或者在框架的情况下:
#import <SomeLibrary/SomeFile.h>
因为Objective-C 是C 编程语言的超集,所以#import 语句是对C 的#include
语句的小改进。 #include 语句非常简单;它会在编译期间将在包含文件中找到的所有内容复制到您的代码中。这有时会导致严重的问题。例如,假设您有两个头文件:SomeFileA.h
和 SomeFileB.h
; SomeFileA.h
包括 SomeFileB.h
,SomeFileB.h
包括 SomeFileA.h
。这会创建一个循环,并且会混淆编译器。为了解决这个问题,C 程序员必须编写防止此类事件发生的防护措施。
使用 #import
时,您无需担心此问题或编写标头保护来避免它。但是,#import
仍然只是一种美化的复制和粘贴操作,在许多其他较小但仍然非常危险的问题中会导致编译时间变慢(例如,包含的文件覆盖了您在自己的代码中其他地方声明的内容。)
模块是解决这个问题的一种尝试。它们不再是复制并粘贴到源代码中,而是包含文件的序列化表示,只有在需要它们的时间和地点才能导入到源代码中。通过使用模块,代码通常会编译得更快,并且比使用 #include 或 #import
更安全。
回到前面导入框架的例子:
#import <SomeLibrary/SomeFile.h>
要将这个库作为模块导入,代码将更改为:
@import SomeLibrary;
这具有 Xcode 将 SomeLibrary 框架自动链接到项目中的额外好处。模块还允许您仅将您真正需要的组件包含到您的项目中。例如,如果您想在 AwesomeLibrary 框架中使用 AwesomeObject 组件,通常您必须导入所有内容才能使用其中的一个。但是,使用模块,您可以只导入要使用的特定对象:
@import AwesomeLibrary.AwesomeObject;
对于在 Xcode 5 中创建的所有新项目,默认启用模块。如果您想在旧项目中使用模块(并且您确实应该),则必须在项目的构建设置中启用它们。完成此操作后,您可以在代码中同时使用 #import
和 @import
语句而无需担心。
@import Module(ObjC) 或语义导入
历史:
#include => #import => Precompiled Headers .pch => @import Module(ObjC); => import Module(Swift)
[#include vs #import]
[Precompiled Headers .pch]
它是 LLVM Modules 的一部分
@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
。自动链接允许基于 #import, @import(Objective-C), import(Swift)
传递 -framework <framework_name>
如果否 - 通过 -fno-autolink
标志
如果您想手动处理系统(#import <UIKit/UIKit.h>
)链接(而不是自动链接),您有两种变体:
将依赖项添加到 General -> Frameworks and Libraries 或 Frameworks, Libraries, and Embedded Content Build Settings -> Other Linker Flags(OTHER_LDFLAGS) -> -framework
在以下情况下引发下一个错误:
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
它目前仅适用于内置系统框架。如果您像苹果一样使用 #import
仍然会在应用程序委托中导入 UIKit
框架,它会被替换(如果模块已打开并且它被识别为系统框架)并且编译器会将其重新映射为模块导入而不是无论如何导入头文件。因此,保留 #import
将与在可能的情况下将其转换为模块导入相同
似乎从 XCode 7.x 开始使用 CLANG_ENABLE_MODULES
启用 clang 模块时会出现很多警告
看看Lots of warnings when building with Xcode 7 with 3rd party libraries
使用模块有一些好处。除非创建了模块映射,否则您只能将它与 Apple 的框架一起使用。 @import
有点类似于添加到 .pch
文件时的预编译头文件,这是一种调整应用程序编译过程的方法。此外,您不必以旧方式添加库,实际上使用 @import
更快更有效。如果您仍在寻找不错的参考资料,我强烈建议您阅读 this article。
@import sqlite3
对我有用,因为我为它创建了自己的 module.map,当我意识到 sqlite 包含在 OS X 中并删除了我的 module.map 时,编译器继续使用过时的模块。