Import all files from a framework? - ios

Is there a way to import all files from a framework, and not just the specific headers you want? This may seem inefficient, but I was just curious if this was possible?

Apple's convention is to use a header within the framework which has the same name as the framework:
#import <Foundation/Foundation.h> // << imports all public headers of Foundation.framework
If the framework in question does not include such a file, you can always write your own.
Even better, you can use modules, which use the syntax: #import Foundation;. This is similar to #import <Foundation/Foundation.h>, but uses a much improved compilation model.
Note: Modules are presently supported in Xcode for Apple's frameworks, although support for user-defined module maps exists in clang. So, hopefully we can define our own modules soon.

Related

How to import a Swift framework globally?

I want to have a way to import my Swift Cocoapods globally in every class, how can I achieve this?
I tried a lot of things and they didn't work. Here are some ways I haven't tried and thought may be possible if found a way to work them:
Have a general import statement like UIKit and put everything in there. (Edit: This failed)
Somehow put Swift frameworks in the Obj-C briding header and import the stuff in there.
You should be able to import it globally by adding #_exported before the import.
#_exported import MyPodModuleName
However, like the other answer mentions, doing that for an entire module is not recommended, because it introduces implicit coupling between modules.
Hence instead try something like:
import Foundation
#_exported import class MyModuleName.MyClassName
#_exported import class MyModuleName.MyOtherClass
It's strongly discouraged in Swift because that would introduce implicit coupling between modules.
However, you can make a certain symbol available globally by declaring a typealias in the module that imports the other module:
import ModuleName
public typealias ClassName = ModuleName.ClassName
As of Swift4:
Being in a Swift project
Want to have another Swift project globally
imported (and using cocoapods)
I just managed to do that by adding the following line to my bridging header:
#import <PodName/PodName-Swift.h>
How good/bad this practise is? Not sure, but I just wanted some extensions globally available in my project. this did the trick.
There is no way to do this. And this is not a bug, this is a language feature (so far, as speaking of Swift 2.2).
Swift uses modules (Apple introduced them in Xcode 5 for Objective-C) and each file is an semantic unit, so you need to explicitly inform Xcode which modules are exposed to defined file.
Not only there is no support for your described behaviour, but you shouldn't also try to bypass it. Using unnecessary (unused) modules could theoretically produce slower code (taking into account that compiler uses this information to its optimisation process).
You can manually achieve the same functionality by:
Creating the Objective-C Bridging Header file;
Adding #import <UIKit/UIKit.h> to the Objective-C Bridging Header file (so that you don't need to repeat this for every single .swift file).
for pods you have to do like #import <SwiftyJSON/SwiftyJSON-umbrella.h>
A reason you wouldn't want to do this:
Imagine if both your frameworks would use the same method name, it would make things ambiguous for the compiler.The compiler won't know which method it should run.
To find out more see this question

Include -Swift.h in the umbrella header

I have a mixed Swift and Objective-C project. To access a Swift public API in Objective-C, the API consumer currently has to import "MyModule-Swift.h". I already have a Objective-C umbrella header called "MyModule.h". But, importing "MyModule.h" is not going to work for the Swift APIs. I tried importing "MyModule-Swift.h" in the umbrella header, but it doesn't find it (I'm assuming since it is generated on the fly by Xcode).
Any suggestions so that an API consumer can always import "MyModule.h" to use public APIs written in Swift/Objective-C will be really appreciated.
====================================================================
Edit: I apologize for not taking the time to properly frame the question. I have a framework called MyModule.
I have a Objective-C class called ABUser,
#interface ABUser: NSObject
- (void)walk;
#end
I wanted to add new behavior to this class using Swift, so I defined an extension
extension ABUser {
func swiftWalk()
}
Now, say I wanted to access the swiftWalk method defined on ABUser from an Objective-C app, I would have to #import <MyModule/MyModule-Swift.h>. #import <MyModule/MyModule.h> would work if I wanted to use the walk method. This is assuming the umbrella header MyModule.h imports ABUser.h.
I always wanted the Objective-C app to #import <MyModule/MyModule.h> and never have to worry about whether an API was written in Objective-C or Swift in the framework. So, I tried importing MyModule-Swift.h in the umbrella header MyModule.h. But, my Objective-C app didn't compile if do that. Not sure, if this is because MyModule-Swift.h is generated by Xcode on the fly during the build process.
Edit 2: Added a sample project to reproduce this issue here: https://github.com/priteshshah1983/MyObjectiveCApp
The relevant code is in ViewController.m. The build will fail with the master branch. To get it work, checkout the working branch.
The reason that using #import MyModule; worked, is that "modules are a packaging together of the framework executable and it's headers" (from this SO post).
In other words, when you #import MyModule;, Objective-C automatically imports all the swift and Objective-C headers related to the module, while you cannot include the swift header from the umbrella header. I suggest you take a look at the differences between #import and #import in the linked SO answer.
It turns out that using #import MyModule; instead of #import <MyModule/Module.h> allows using walk and swiftWalk methods as expected from the Objective-C app.
I honestly don't understand the details, but I hope this helps someone else. Please feel free to explain!

Can I use the new #import directive to import custom frameworks?

I was happy to see the new #import directive in Objective-C, but I lived under the impression it could not be currently used to import custom frameworks (one source). But I have just created a custom Cocoa Framework in Xcode 6 (are these supported now?) and I can #import it just fine. What gives?
Yes you can use #import in Xcode 6. From New Features in Xcode 6 Beta:
User-defined modules. Developers are now able to define modules for
their own Objective-C code, making it easier than ever for them to
share frameworks across all their projects. By combining user-defined
modules with Swift’s automatic creation of modules, the two languages
work together seamlessly.
There are more details in the WWDC 2014 video "What's New in LLVM", page 25 of the PDF:
http://devstreaming.apple.com/videos/wwdc/2014/417xx2zsyyp8zcs/417/417_whats_new_in_llvm.pdf?dl=1

Objective C #import for modules does it replace #import?

The new syntax in Objective-C in Xcode 5 is #importto import a framework.
See question for details. Advantage is that you don't have to include the framework in project avoiding linker errors, you don't need to add quotes and .h to just the name of the framework, it is faster for precompiled headers, and you have a namespace that protects you from accidentally renaming a symbol. All nice additions.
My question is, for your own files, for example MyFancyViewController.h, do you continue to use #import or does #import completely replace it? Also, can I define my own modules easily? Just looks more messy having both syntaxes in the same file.
for you including of your project files do you continue to use #import or does #import completely replace it?
#import, so far, is for Apple frameworks only, so at the time of writing you still have to use #import for anything else.
The good news is that, if you opt-in, any #import will be implicitly replaced for you by the compiler, so you don't need to convert your previous code to benefit from modules.
Also, can I define my own modules easily?
Yes and no.
Yes, it's easy, but...
...no you cannot, since this feature is currently not supported for non-Apple frameworks.
To define your own module - if you could - you would need to do:
export MyAwesomeModule:
public:
// methods and whatever you want to export
#import is for official frameworks only. For MyFancyViewController.h continue use #import.

#import vs #import - iOS 7

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?
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:
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.
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.
#import Module(ObjC) or Semantic import
instead of usual module using
//as example
#include <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
History:
[#include -> #import] -> [Precompiled Headers .pch] -> #import Module(ObjC); -> [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
CLANG_ENABLE_MODULES == NO and CLANG_MODULES_AUTOLINK == NO
If you want to handle system(#import <UIKit/UIKit.h>) linking manually(instead of auto-linking) you have two variants:
Add dependency into General -> Frameworks and Libraries or Frameworks, Libraries, and Embedded Content
Build Settings -> Other Linker Flags(OTHER_LDFLAGS) -> -framework <module_name>
Next error will be thrown if:
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
CLANG_ENABLE_MODULES is disabled
CLANG_MODULES_AUTOLINK is disabled and no manual linking
Reverse engineering
otool -l <binary>
//-l print the load commands
//find LC_LINKER_OPTION
//cmd LC_LINKER_OPTION
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
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
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.

Resources