繁体   English   中英

@import 与 #import - iOS 7

[英]@import vs #import - iOS 7

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

@import UIKit;

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

这是一个称为模块或“语义导入”的新功能。 Session 205404WWDC 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.hSomeFileB.h SomeFileA.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语句而不必担心。

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

@import Module(ObjC) 或语义导入

历史:

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

[#include 与 #import]
[预编译头文件 .pch]

[导入模块(Swift)]

它是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> )链接(而不是自动链接),您有两种变体:

  1. 将依赖项添加到General -> Frameworks and Libraries or Frameworks, Libraries, and Embedded Content

  2. 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 模块时会出现很多警告

使用带有 3rd 方库的 Xcode 7 进行构建时查看大量警告

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

模块 [Structure]提供了一种更好的方式来处理系统框架和库,方法是将预处理器文本包含机制替换为Clang所称的语义导入。 要导入模块,请使用@import声明而不是#include#import预处理器指令

当编译器看到模块导入@import它会加载二进制文件的独立precompiled版本。 它还会自动处理链接到模块,这意味着您不再需要在Xcode中手动添加框架。 由于模块只编译一次,因此在prefix.pch中包含框架头不再有任何优势。 因此,Precompile Prefix Header构建设置现在在Xcode中默认为NO。

@import解决了以下问题:

  • 导入框架的完整语义描述
  • 不需要解析头文件
  • 加载二进制表示
  • 比预编译头更灵活
  • 无需维护.pch文件

#import#include指令在后台自动转换为@import ,无需任何工作即可为您提供模块的优势。

当你构建自己的framework ,Xcode将生成一个包含umbrella header的模块图[关于]

使用Objective-C构建自己的library ,需要创建自己的模块映射( .modulemap )并确保其内容是最新的。 [创建库] [setup modulemap] [自定义模块映射]

#mport vs #include

这里阅读更多内容

@import SomeLibrary不工作时SomeLibrary是斯威夫特包。 #import <SomeLibrary/SomeLibrary.h>#import "SomeLibrary-Swift.h"

有没有人有解决方案? 谢谢。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM