By Kevin McNeish on Fri, 06/20/2014
Even though Apple has provided the new Swift programming language for building iOS apps, one thing remains the same—we still use the Cocoa Touch Framework libraries to build iOS functionality into our apps. However, since the Cocoa Touch Framework is written in Objective-C, how is this accomplished? In this article I'll show you the mechanics behind how Swift accesses Objective-C code, and how the Cocoa Touch APIs (application programming interfaces) change when you access them from Swift.
Swift and Objective-C Interoperability
Apple has done a great job of making it easy for you to access Objective-C code from Swift, and to access Swift code from Objective-C. In fact, a single Xcode project can contain both Objective-C and Swift code files. This is great news for those of us who have many apps and code libraries written in Objective-C.
This interoperability allows you to slowly migrate your apps to Swift without rewriting the entire app or waiting for Swift versions of third-party libraries you are using. It also allows you to access the power of the Cocoa Touch Framework. This is important when working in a new language such as Swift, which will take some time to fully mature.
Importing Cocoa Touch Frameworks
In a Swift project, you no longer need to add Cocoa Touch frameworks to your project by means of the Project Editor. Instead, all you have to do is add an import statement at the top of your Swift code file followed by the name of the Cocoa Touch framework you want to import. For example, the following code imports the Cocoa Touch Foundation and Media Player frameworks:
It's as easy as that!
When you import an Objective-C framework into a project (Figure 1) the framework's header files are compiled into Objective-C modules, which are then imported as Swift APIs.
This import process makes changes to the classes, methods, and functions so they look like Swift classes. For example, the types of method argument and return values are changed to Swift types.
So, for example, a Cocoa Touch Framework method that returns NSString in Objective-C returns the Swift String type instead. As another example, enumerations change from the Objective-C style shown here:
To the new Swift enumeration style:
Once you have imported an Objective-C framework into your project, you can instantiate classes from the framework and access their functionality using native Swift syntax.
Creating Objects from Objective-C Classes in Swift
When you create objects from Cocoa Touch Framework classes in Swift, you can see that changes were made to the class initializer methods when they were imported to Swift.
By way of comparison, here is how you instantiate a UIImageView in Objective-C using the initWithImage: initializer:
UIImageView *imageView = [[UIImageView alloc] initWithImage:myImage];
The equivalent code in Swift looks like this:
var myImageView:UIImageView = UIImageView(image: myImage)
Here are the important differences to note:
- You don't call alloc in Swift because Swift handles this for you.
- The initWith prefix gets removed from the initWithImage name (init or initWith is removed based on the initializer name.)
- The remainder of the initializer name (Image) is placed between parentheses, its first character is lowercased and is used as the name of the first argument.
- Any additional Objective-C arguments are also converted to argument names and are included between the parentheses.
When creating an instance of a class in Swift, you don't need to specify the type of the variable because Swift is able to figure out, or infer, the type for you:
var myImageView = UIImageView(image: myImage)
Creating Objects from Objective-C Factory Methods in Swift
Many Objective-C classes have factory methods that combine alloc and init in one step and return a new object (they are called factory methods because they manufacture, or create objects.) For example, the following Objective-C code shows a factory method that returns a UIImage object:
UIImage *myImage = [UIImage imageNamed:@"pause.png"];
When factory methods are imported into Swift, they are converted to initializer methods like this:
var myImage = UIImage(named: "pause.png")
Notice that the imageNamed parameter is changed to named in Swift.
Accessing Objective-C Properties in Swift
When accessing properties in Objective-C, you can choose from two different syntaxes. You can either send a message using square brackets or use dot syntax (.) to access the property
In Swift, you always access properties using dot syntax. For example:
controller.fullscreen = false
When an Objective-C class is imported into Swift, only its properties that have been declared using the @property declaration are converted to properties in Swift. Any method declared as an implicit getter (a method that accepts no parameters and returns a value) are imported as methods.
Calling Methods in Swift
In Swift, you also call methods using dot syntax. For example, the following code calls the pause method on a controller object.
When calling a method that has just one parameter, it's typical that you simply pass an argument like this:
var suffixFound = myString.hasPrefix("txt")
If a method has multiple parameters, the rest of the parameters are named and you use syntax similar to Objective-C when passing the arguments. For example, in the following method call, the first argument has no name, but for the second argument you specify the name followed by a colon (animated:) followed by the argument (true):
tableView.deselectRowAtIndexPath(indexPath animated: true)
Calling Objective-C Methods in Swift
When an Objective-C class is imported into Swift, the method name and arguments are changed to adapt to Swift method syntax.
For example, the following Objective-C message call:
[self performSegueWithIdentifier:@"MySegue" sender:self];
Looks like this in Swift:
self.performSegueWithIdentifier("MySegue", sender: self)
Here are the main points to note:
- You use dot syntax (.) to call the method.
- The first part of the Objective-C selector (performSegueWithIdentifier) becomes the method name.
- The first argument ("MySegue") appears insides the parentheses and doesn't have a name.
- All other parts of the selector (for example, sender:) become argument names and are included in the parentheses.
The interoperability that Apple has provided for Swift makes it much easier for Objective-C developers to step over into this new language. Even though the syntax has changed a bit it's still recognizable, and Xcode's Code Completion helps considerably as you shift your brain over to Swift!