@import vs #import——iOS 7

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

@import UIKit;

我想我在另一个视频中看到了一些关于这个的东西,但我很难找到它。我在找什么时候使用这个的背景资料。它只能用于苹果框架吗?使用这个编译器指令的好处是否足够让我回去更新旧代码?

141442 次浏览

这是一个名为模块或“语义导入”的新特性。有关会话205404WWDC 2013视频中有更多信息。这是预编译头文件的更好实现。你可以在iOS 7和Mavericks中的任何系统框架中使用模块。模块是框架可执行文件及其头文件的打包,被吹捧为比#import更安全、更高效。

使用@import的最大优点之一是你不需要在项目设置中添加框架,这是自动完成的. xml。这意味着您可以跳过单击加号按钮并搜索框架(黄金工具箱)的步骤,然后将其移动到“框架”。组。它将使许多开发人员从神秘的“链接错误”中解脱出来。消息。

你实际上不需要使用@import关键字。如果你选择使用模块,所有#import#include指令都会自动映射为使用@import。这意味着您不必更改源代码(或从其他地方下载的库的源代码)。据说使用模块也可以提高构建性能,特别是如果您没有很好地使用PCHs,或者如果您的项目有许多小的源文件。

模块是为大多数苹果框架(UIKit, MapKit, GameKit等)预先构建的。你可以在你自己创建的框架中使用它们:如果你在Xcode中创建一个Swift框架,它们会自动创建,你可以手动创建一个" modulemap"自己申请任何苹果或第三方库

你可以使用代码完成来查看可用框架的列表:

enter image description here

在Xcode 5的新项目中,模块默认是启用的。要在旧项目中启用它们,请进入项目构建设置,搜索“模块”;并设置“;启用模块”;YES"“帮助”。“链接框架”;应该是“;YES":

 .

你必须使用Xcode 5和iOS 7或Mavericks SDK,但你仍然可以发布旧的操作系统(比如iOS 4.3或其他)。模块不会改变代码的构建方式或任何源代码。


来自WWDC的幻灯片:

  • 导入框架的完整语义描述
  • 不需要解析头文件
  • 导入框架接口的更好方法
  • 加载二进制表示
  • 比预编译头文件更灵活
  • 不受本地宏定义的影响(例如#define readonly 0x01)
  • 默认为新项目启用

要显式地使用模块:

@import Cocoa;替换#import <Cocoa/Cocoa.h>

你也可以用下面的符号只导入一个头文件:

@import iAd.ADBannerView;

子模块在Xcode中自动完成。

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

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

你可以在《用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.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语句,而不用担心任何问题。

似乎自从XCode 7。x .当使用CLANG_ENABLE_MODULES启用clang模块时,会出现很多警告

看看在使用Xcode 7和第三方库构建时,有很多警告

@import模块(ObjC)或语义导入

历史:

#include => #import => Precompiled Headers .pch => @import Module(ObjC); => import Module(Swift)
< p > [#include vs #import]
[预编译Headers .pch]
< / p >

(导入模块(斯威夫特))

它是LLVM模块的一部分

@import <module_name>;声明告诉编译器负载(而不是编译)模块的预编译二进制文件减少建造时间。以前编译器编译依赖每次当runt进入它,但现在它应该事先编译,只是加载

//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>

如果NO -传递-fno-autolink标志

如果你想手动处理system(#import <UIKit/UIKit.h>)链接(而不是自动链接),你有两个变量:

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

  2. < p > 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