ChatGPT解决这个技术问题 Extra ChatGPT

@import 与 #import - iOS 7

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

@import UIKit;

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

不幸的是,对于 .mm 个文件,或者更确切地说是 Objective-C++@importnot supported yet(我对 g++clang++ 都进行了测试,因为我真的很想完成这项工作)。

n
nevan king

这是一个名为Modules 或“语义导入”的新功能。会议 205404WWDC 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 中的子模块会自动完成。


@DaveDeLong &克拉斯:谢谢!我不得不承认,当我第一次回答这个问题时,我对模块一无所知。我去看了第 404 课来学习它。 Doug Gregor(LLVM 人)的演讲做得非常好。还有一个 C++ Modules talk 解释了这里的优点:youtube.com/watch?v=4Xo9iH5VLQ0
@nevan--感谢您的回答。我只是想补充一点,模块目前还不支持 3rd 方和您自己的框架。
您可以将其用于您自己的课程吗?
如果提供了适当的 module.map,我认为您应该能够@import 3rd 方框架。 LLVM clang 模块文档:clang.llvm.org/docs/Modules.html#module-map-language
哦,实际上它看起来像 @import sqlite3 对我有用,因为我为它创建了自己的 module.map,当我意识到 sqlite 包含在 OS X 中并删除了我的 module.map 时,编译器继续使用过时的模块。
h
hbk

很好的答案可以在《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.hSomeFileB.hSomeFileA.h 包括 SomeFileB.hSomeFileB.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 语句而无需担心。


我的项目(Xcode 6)中没有我第一次在 Xcode 4 上启动用于启用模块的选项。我可以以某种方式手动添加吗?
构建目标是iOS 6,我认为这是问题
y
yoAlex5

@import Module(ObjC) 或语义导入

历史:

#include => #import => Precompiled Headers .pch => @import Module(ObjC); => import Module(Swift)

[#include vs #import]
[Precompiled Headers .pch]

[import Module(Swift)]

它是 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 指令自动转换为具有所有优势的 @importModulemap 允许无缝执行,因为包含标题和子/模块之间的映射

通过-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

R
RyanTCB

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


l
loretoparisi

似乎从 XCode 7.x 开始使用 CLANG_ENABLE_MODULES 启用 clang 模块时会出现很多警告

看看Lots of warnings when building with Xcode 7 with 3rd party libraries


是的,我也有这个问题,但是将其设置为 NO 会删除所有警告。这样做会不会有副作用??
J
Julian

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