iOS Developer Library — Prerelease

Developer

Using Swift with Cocoa and Objective-C

iBooks
On This Page

Writing Swift Classes with Objective-C Behavior

Interoperability lets you define Swift classes that incorporate Objective-C behavior. You can subclass Objective-C classes, adopt Objective-C protocols, and take advantage of other Objective-C functionality when writing a Swift class. This means that you can create classes based on familiar, established behavior in Objective-C and enhance them with Swift’s modern and powerful language features.

Inheriting from Objective-C Classes

In Swift, you can define subclasses of Objective-C classes. To create a Swift class that inherits from an Objective-C class, add a colon (:) after the name of the Swift class, followed by the name of the Objective-C class.

  1. import UIKit
  2. class MySwiftViewController: UIViewController {
  3. // define the class
  4. }

You get all the functionality offered by the superclass in Objective-C. If you provide your own implementations of the superclass’s methods, remember to use the override keyword.

NSCoding

The NSCoding protocol requires that conforming types implement the required initializer init(coder:). Classes that adopt NSCoding directly must implement this method. Subclasses of classes that adopt NSCoding that have one or more custom initializers or any properties without initial values must also implement this method. Xcode provides the following fix-it to serve as a placeholder implementation:

  1. required init(coder aDecoder: NSCoder) {
  2. fatalError("init(coder:) has not been implemented")
  3. }

For objects that are loaded from Storyboards or archived to disk using the NSUserDefaults or NSKeyedArchiver classes, you must provide a full implementation of this initializer. However, you might not need to implement an initializer for types that are expected to or cannot be instantiated in this way.

Adopting Protocols

In Swift, you can adopt protocols that are defined in Objective-C. Like Swift protocols, any Objective-C protocols go in a comma-separated list following the name of a class’s superclass, if any.

  1. class MySwiftViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
  2. // define the class
  3. }

Objective-C protocols come in as Swift protocols. If you want to refer to the UITableViewDelegate protocol in Swift code, refer to it as UITableViewDelegate (as compared to id<UITableViewDelegate> in Objective-C).

Because the namespace of classes and protocols is unified in Swift, the NSObject protocol in Objective-C is remapped to NSObjectProtocol in Swift.

Writing Initializers and Deinitializers

The Swift compiler ensures that your initializers do not leave any properties in your class uninitialized to increase the safety and predictability of your code. Additionally, unlike Objective-C, in Swift there is no separate memory allocation method to invoke. You use native Swift initialization syntax even when you are working with Objective-C classes—Swift converts Objective-C initialization methods to Swift initializers. You can read more about implementing your own initializers in Initializers.

When you want to perform additional clean-up before your class is deallocated, you can implement a deninitializer instead of the dealloc method. Swift deinitializers are called automatically, just before instance deallocation happens. Swift automatically calls the superclass deinitializer after invoking your subclass’ deinitializer. When you are working with an Objective-C class or your Swift class inherits from an Objective-C class, Swift calls your class’s superclass dealloc method for you as well. You can read more about implementing your own deinitializers in Deinitializers in The Swift Programming Language.

Integrating with Interface Builder

The Swift compiler includes attributes that enable Interface Builder features for your Swift classes. As in Objective-C, you can use outlets, actions, and live rendering in Swift.

Working with Outlets and Actions

Outlets and actions allow you to connect your source code to user interface objects in Interface Builder. To use outlets and actions in Swift, insert @IBOutlet or @IBAction just before the property or method declaration. You use the same @IBOutlet attribute to declare an outlet collection—just specify an array for the type.

When you declare an outlet in Swift, you should make the type of the outlet an implicitly unwrapped optional. This way, you can let the storyboard connect the outlets at runtime, after initialization. When your class is initialized from a storyboard or xib file, you can assume that the outlet has been connected.

For example, the following Swift code declares a class with an outlet, an outlet collection, and an action:

  1. class MyViewController: UIViewController {
  2. @IBOutlet weak var button: UIButton!
  3. @IBOutlet var textFields: [UITextField]!
  4. @IBAction func buttonTapped(AnyObject) {
  5. print("button tapped!")
  6. }
  7. }

Because the sender parameter of the buttonTapped method wasn’t used, the parameter name can be omitted.

Live Rendering

You can use two different attributes—@IBDesignable and @IBInspectable—to enable live, interactive custom view design in Interface Builder. When you create a custom view that inherits from the UIView class or the NSView class, you can add the @IBDesignable attribute just before the class declaration. After you add the custom view to Interface Builder (by setting the custom class of the view in the inspector pane), Interface Builder renders your view in the canvas.

You can also add the @IBInspectable attribute to properties with types compatible with user defined runtime attributes. After you add your custom view to Interface Builder, you can edit these properties in the inspector.

  1. @IBDesignable
  2. class MyCustomView: UIView {
  3. @IBInspectable var textColor: UIColor
  4. @IBInspectable var iconHeight: CGFloat
  5. /* ... */
  6. }

Specifying Property Attributes

In Objective-C, properties have a range of potential attributes that specify additional information about a property’s behavior. In Swift, you specify these property attributes in a different way.

Strong and Weak

Swift properties are strong by default. Use the weak keyword to indicate that a property has a weak reference to the object stored as its value. This keyword can be used only for properties that are optional class types. For more information, see Attributes.

Read/Write and Read-Only

In Swift, there are no readwrite and readonly attributes. When declaring a stored property, use let to make it read-only, and use var to make it read/write. When declaring a computed property, provide a getter only to make it read-only and provide both a getter and setter to make it read/write. For more information, see Properties in The Swift Programming Language.

Copy Semantics

In Swift, the Objective-C copy property attribute translates to @NSCopying. The type of the property must conform to the NSCopying protocol. For more information, see Attributes in The Swift Programming Language.

Implementing Core Data Managed Object Subclasses

Core Data provides the underlying storage and implementation of properties in subclasses of the NSManagedObject class. Add the @NSManaged attribute before each property definition in your managed object subclass that corresponds to an attribute or relationship in your Core Data model. Like the @dynamic attribute in Objective-C, the @NSManaged attribute informs the Swift compiler that the storage and implementation of a property is provided at runtime. However, unlike @dynamic, the @NSManaged attribute is available only for Core Data support.

Swift classes are namespaced—they’re scoped to the module (typically, the target) they are compiled in. To use a Swift subclass of the NSManagedObject class with your Core Data model, prefix the class name in the Class field in the model entity inspector with the name of your module.

image: ../Art/coredatanamespace_2x.png

Using Swift Class Names with Objective-C APIs

Swift classes are namespaced based on the module they are compiled in, even when used from Objective-C code. Unlike Objective-C, where all classes are part of a global namespace–and must not have the same name–Swift classes can be disambiguated based on the module they reside in. For example, the fully qualified name of a Swift class named DataManager in a framework named MyFramework is MyFramework.DataManager. A Swift app target is a module itself, so the fully qualified name of a Swift class named Observer in an app called MyGreatApp is MyGreatApp.Observer.

In order to preserve namespacing when a Swift class is used in Objective-C code, Swift classes are exposed to the Objective-C runtime with their fully qualified names. Therefore, when you work with APIs that operate on the string representation of a Swift class, you must include the fully qualified name of the class. For example, when you create a document–based Mac app, you provide the name of your NSDocument subclass in your app’s Info.plist file. In Swift, you must use the full name of your document subclass, including the module name derived from the name of your app or framework.

In the example below, the NSClassFromString function is used to retrieve a reference to a class from its string representation. In order to retrieve a Swift class, the fully qualified name, including the name of the app, is used.

  1. let myPersonClass: AnyClass = NSClassFromString("MyGreatApp.Person")