[英]@import vs #import - iOS 7
我正在尝试一些新的 iOS 7 功能并使用一些图像效果,如 WWDC 视频“在 iOS 上实现引人入胜的 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 中为您自动完成。
您可以在使用 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
仍然在应用程序委托中导入UIKit
框架,它会被替换(如果模块打开并且它被识别为系统框架)并且编译器会将它重新映射为模块导入而不是导入无论如何,头文件。 所以离开#import
将与它转换为模块导入一样,无论如何
@import Module(ObjC) 或语义导入
历史:
#include => #import => Precompiled Headers .pch => @import Module(ObjC); => import Module(Swift)
[#include 与 #import]
[预编译头文件 .pch]
它是LLVM 模块的一部分
@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 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.xa 使用CLANG_ENABLE_MODULES
启用 clang 模块时会出现很多警告
使用模块有几个好处。 除非创建了模块映射,否则您只能在 Apple 的框架中使用它。 @import
添加到.pch
文件时有点类似于预编译头文件,这是一种调整应用程序编译过程的方法。 此外,您不必以旧方式添加库,实际上使用@import
更快更高效。 如果您仍在寻找不错的参考资料,我强烈建议您阅读这篇文章。
模块 [Structure]提供了一种更好的方式来处理系统框架和库,方法是将预处理器文本包含机制替换为Clang所称的语义导入。 要导入模块,请使用@import
声明而不是#include
或#import
预处理器指令
当编译器看到模块导入@import
它会加载二进制文件的独立precompiled
版本。 它还会自动处理链接到模块,这意味着您不再需要在Xcode中手动添加框架。 由于模块只编译一次,因此在prefix.pch中包含框架头不再有任何优势。 因此,Precompile Prefix Header构建设置现在在Xcode中默认为NO。
@import
解决了以下问题:
#import
和#include
指令在后台自动转换为@import
,无需任何工作即可为您提供模块的优势。
当你构建自己的framework
,Xcode将生成一个包含umbrella header
的模块图[关于]
使用Objective-C构建自己的library
,需要创建自己的模块映射( .modulemap )并确保其内容是最新的。 [创建库] [setup modulemap] [自定义模块映射]
@import SomeLibrary
不工作时SomeLibrary是斯威夫特包。 #import <SomeLibrary/SomeLibrary.h>
或#import "SomeLibrary-Swift.h"
有没有人有解决方案? 谢谢。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.