439

I am playing around with some of the new iOS 7 features and working with some of the Image Effects as discussed in the WWDC video "Implementing Engaging UI on iOS". For producing a blur effect within the source code for the session, UIImage was extended via a category which imports UIKit like so:

@import UIKit;

I think I saw something about this in another session video but I'm having trouble finding it. I'm looking for any background information on when to use this. Can it only be used with Apple frameworks? Are the benefits of using this compiler directive enough that I should go back and update old code?

Cœur
  • 32,421
  • 21
  • 173
  • 232
jamdaddy25
  • 4,628
  • 3
  • 11
  • 11

6 Answers6

849

It's a new feature called Modules or "semantic import". There's more info in the WWDC 2013 videos for Session 205 and 404. It's kind of a better implementation of the pre-compiled headers. You can use modules with any of the system frameworks in iOS 7 and Mavericks. Modules are a packaging together of the framework executable and its headers and are touted as being safer and more efficient than #import.

One of the big advantages of using @import is that you don't need to add the framework in the project settings, it's done automatically. That means that you can skip the step where you click the plus button and search for the framework (golden toolbox), then move it to the "Frameworks" group. It will save many developers from the cryptic "Linker error" messages.

You don't actually need to use the @import keyword. If you opt-in to using modules, all #import and #include directives are mapped to use @import automatically. That means that you don't have to change your source code (or the source code of libraries that you download from elsewhere). Supposedly using modules improves the build performance too, especially if you haven't been using PCHs well or if your project has many small source files.

Modules are pre-built for most Apple frameworks (UIKit, MapKit, GameKit, etc). You can use them with frameworks you create yourself: they are created automatically if you create a Swift framework in Xcode, and you can manually create a ".modulemap" file yourself for any Apple or 3rd-party library.

You can use code-completion to see the list of available frameworks:

enter image description here

Modules are enabled by default in new projects in Xcode 5. To enable them in an older project, go into your project build settings, search for "Modules" and set "Enable Modules" to "YES". The "Link Frameworks" should be "YES" too:

You have to be using Xcode 5 and the iOS 7 or Mavericks SDK, but you can still release for older OSs (say iOS 4.3 or whatever). Modules don't change how your code is built or any of the source code.


From the WWDC slides:

  • Imports complete semantic description of a framework
  • Doesn't need to parse the headers
  • Better way to import a framework’s interface
  • Loads binary representation
  • More flexible than precompiled headers
  • Immune to effects of local macro definitions (e.g. #define readonly 0x01)
  • Enabled for new projects by default

To explicitly use modules:

Replace #import <Cocoa/Cocoa.h> with @import Cocoa;

You can also import just one header with this notation:

@import iAd.ADBannerView;

The submodules autocomplete for you in Xcode.

nevan king
  • 108,735
  • 42
  • 196
  • 237
  • 15
    @DaveDeLong & Klaas: Thanks! I have to admit that I knew nothing about modules when I first answered this. I went and watched Session 404 to learn it. The presentation that Doug Gregor (the LLVM guy) gave was really well done. There's also a C++ Modules talk where explains the advantages here: http://www.youtube.com/watch?v=4Xo9iH5VLQ0 – nevan king Sep 23 '13 at 10:00
  • 3
    @nevan-- thanks for the answer. I just wanted to add that modules does not currently support 3rd party and your own frameworks yet. – jamdaddy25 Sep 25 '13 at 15:42
  • Can you use this for your own classes? – cfischer Oct 07 '13 at 09:54
  • I just want to point out that if you're adding it to an older project, you have to edit the project build build settings, not the target build settings. – Moshe Oct 11 '13 at 21:17
  • @urimoai-you can't use this with your own classes. – jamdaddy25 Oct 24 '13 at 13:39
  • Hooray! Hello, `pythonic` style! :) – skywinder Nov 07 '13 at 15:55
  • Just a thing: though linking frameworks is done automatically, some features like Game Center or MapKit on OS X require extra setup beyond linking before they can work -- you can have Xcode do that for you by turning on the appropriate switches under your app target > Capabilities. – millenomi Nov 13 '13 at 15:02
  • 5
    I think you should be able to @import 3rd party frameworks if an appropriate module.map is provided. The LLVM clang module documentation: http://clang.llvm.org/docs/Modules.html#module-map-language – bames53 Nov 20 '13 at 14:00
  • @bames53 I tried but couldn't with the sqlite3 library. Let me know if you get it working and I'll update the answer. – nevan king Nov 20 '13 at 14:16
  • @nevanking Do you mean you tried to write a module.map and it didn't work? – bames53 Nov 20 '13 at 14:19
  • @bames53 No, nothing like that. I just tried to (@)import the sqlite3 library. I have no idea how to make a module map. – nevan king Nov 20 '13 at 14:26
  • @nevanking That link I gave describes it, and you can look at Apple's module.map files for examples. sqlite3 happens to be included already so `@import sqlite3` already works. I tried creating a module with a trivial library of my own and it worked fine. – bames53 Nov 20 '13 at 15:45
  • @bames53 I tried `@import sqlite` again, but it gave an error. Module 'sqlite' not found. – nevan king Nov 20 '13 at 19:43
  • @nevanking `@import sqlite3` – bames53 Nov 20 '13 at 19:45
  • 1
    Oh, actually it looks like `@import sqlite3` worked for me because I had created my own module.map for it and when I realized sqlite was included in OS X and removed my module.map, the compiler continued using the stale module. – bames53 Nov 21 '13 at 14:25
  • @NicolasMiari Looks like something screwy in the Apple site. Click the link above for 404, then click the "Advances in Objective-C" title twice and it shows up. – nevan king Mar 12 '14 at 14:52
  • @nevanking Sorry, it was a only joke: 404 -> Not Found (get it?). But thanks for the detailed explanation :) – Nicolas Miari Mar 13 '14 at 01:03
  • By the way, it is now possible to use `@import` with custom frameworks (that have been introduced with iOS 8). As pointed out earlier, modules aren't Objectice-C only either so you should be able to use it with any language that Clang compiles, and for dynamic and static libraries, although the latter will require some custom fiddling with the module maps. – hagi Oct 18 '14 at 07:19
  • For a legacy project, it's a good idea and safe to go and replace all `#import`s with `@import`s? – Iulian Onofrei Jan 20 '15 at 15:15
  • Haven't realized this feature yet! Thanks for the answer and the nice video found by @nevanking http://youtube.com/watch?v=4Xo9iH5VLQ0 – Hao Xi Sep 26 '16 at 09:19
  • Is there any drawback of using @import over #import? – Rajesh Budhiraja May 27 '21 at 09:03
46

Nice answer you can find in book Learning Cocoa with Objective-C (ISBN: 978-1-491-90139-7)

Modules are a new means of including and linking files and libraries into your projects. To understand how modules work and what benefits they have, it is important to look back into the history of Objective-C and the #import statement Whenever you want to include a file for use, you will generally have some code that looks like this:

#import "someFile.h"

Or in the case of frameworks:

#import <SomeLibrary/SomeFile.h>

Because Objective-C is a superset of the C programming language, the #import state‐ ment is a minor refinement upon C’s #include statement. The #include statement is very simple; it copies everything it finds in the included file into your code during compilation. This can sometimes cause significant problems. For example, imagine you have two header files: SomeFileA.h and SomeFileB.h; SomeFileA.h includes SomeFileB.h, and SomeFileB.h includes SomeFileA.h. This creates a loop, and can confuse the coimpiler. To deal with this, C programmers have to write guards against this type of event from occurring.

When using #import, you don’t need to worry about this issue or write header guards to avoid it. However, #import is still just a glorified copy-and-paste action, causing slow compilation time among a host of other smaller but still very dangerous issues (such as an included file overriding something you have declared elsewhere in your own code.)

Modules are an attempt to get around this. They are no longer a copy-and-paste into source code, but a serialised representation of the included files that can be imported into your source code only when and where they’re needed. By using modules, code will generally compile faster, and be safer than using either #include or #import.

Returning to the previous example of importing a framework:

#import <SomeLibrary/SomeFile.h>

To import this library as a module, the code would be changed to:

@import SomeLibrary;

This has the added bonus of Xcode linking the SomeLibrary framework into the project automatically. Modules also allow you to only include the components you really need into your project. For example, if you want to use the AwesomeObject component in the AwesomeLibrary framework, normally you would have to import everything just to use the one piece. However, using modules, you can just import the specific object you want to use:

@import AwesomeLibrary.AwesomeObject;

For all new projects made in Xcode 5, modules are enabled by default. If you want to use modules in older projects (and you really should) they will have to be enabled in the project’s build settings. Once you do that, you can use both #import and @import statements in your code together without any concern.

hbk
  • 9,872
  • 9
  • 82
  • 110
4

It currently only works for the built in system frameworks. If you use #import like apple still do importing the UIKit framework in the app delegate it is replaced (if modules is on and its recognised as a system framework) and the compiler will remap it to be a module import and not an import of the header files anyway. So leaving the #import will be just the same as its converted to a module import where possible anyway

RyanTCB
  • 5,944
  • 3
  • 36
  • 55
2

It seems that since XCode 7.x a lot of warnings are coming out when enabling clang module with CLANG_ENABLE_MODULES

Take a look at Lots of warnings when building with Xcode 7 with 3rd party libraries

loretoparisi
  • 12,864
  • 9
  • 78
  • 108
  • Yes I too have this issue, but setting it to NO removes all the warnings. Will there be a side effect when I do this?? – Satheesh Oct 16 '15 at 06:47
1

There is a few benefits of using modules. You can use it only with Apple's framework unless module map is created. @import is a bit similar to pre-compiling headers files when added to .pch file which is a way to tune app the compilation process. Additionally you do not have to add libraries in the old way, using @import is much faster and efficient in fact. If you still look for a nice reference I will highly recommend you reading this article.

Julian
  • 8,989
  • 4
  • 45
  • 63
1

@import Module(ObjC) or Semantic import

History:

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

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

[import Module(Swift)]

It is a part of LLVM Modules

@import <module_name>; declaration says to compiler to load(instead of compile) a precompiled binary of module which decrease a building time. Previously compiler compiled dependency every time when runt into it but now it should be compiled beforehand and just loaded

//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] - bridge between module and headers

Xcode

Enable Modules(C and Objective-C)(CLANG_ENABLE_MODULES) - CLANG #include, #import directives are automatically converted to @import that brings all advantages. Modulemap allows to do it seamless because contains a map between headers and sub/modules

Pass -fmodules

#include, #import -> @import

Link Frameworks Automatically(CLANG_MODULES_AUTOLINK) - enables system modules auto linking. Requires activated CLANG_ENABLE_MODULES. Auto-linking allows to pass -framework <framework_name> based on #import, @import(Objective-C), import(Swift)

If NO - passes -fno-autolink flag

If you want to handle system(#import <UIKit/UIKit.h>) linking manually(instead of auto-linking) you have two variants:

  1. Add dependency into General -> Frameworks and Libraries or Frameworks, Libraries, and Embedded Content

  2. Build Settings -> Other Linker Flags(OTHER_LDFLAGS) -> -framework <module_name>

Trows next error if:

  • CLANG_ENABLE_MODULES is disabled
  • CLANG_MODULES_AUTOLINK is disabled and no manual linking
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

Reverse engineering

otool -l <binary> 
//-l print the load commands
//find LC_LINKER_OPTION
//cmd LC_LINKER_OPTION
yoAlex5
  • 13,571
  • 5
  • 105
  • 98