Article

Using Objective-C Runtime Features in Swift

Use selectors and key paths to interact with dynamic Objective-C APIs.

Overview

Some Objective-C APIs—like target-action—accept method or property names as parameters, then use those names to dynamically call or access the methods or properties. In Swift, you use the #selector and #keyPath expressions to represent those method or property names as selectors or key paths, respectively.

Use Selectors to Arrange Calls to Objective-C Methods

In Objective-C, a selector is a type that refers to the name of an Objective-C method. In Swift, Objective-C selectors are represented by the Selector structure, and you create them using the #selector expression.

In Swift, you create a selector for an Objective-C method by placing the name of the method within the #selector expression: #selector(MyViewController.tappedButton(_:)). To construct a selector for a property’s Objective-C getter or setter method, prefix the property name using the getter: or setter: label, like #selector(getter: MyViewController.myButton). The example below shows a selector being used as part of the target-action pattern to call a method in response to the touchUpInside event.

import UIKit
class MyViewController: UIViewController {
    let myButton = UIButton(frame: CGRect(x: 0, y: 0, width: 100, height: 50))
    
    override init(nibName nibNameOrNil: NSNib.Name?, bundle nibBundleOrNil: Bundle?) {
        super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
        let action = #selector(MyViewController.tappedButton)
        myButton.addTarget(self, action: action, forControlEvents: .touchUpInside)
    }
    
    @objc func tappedButton(_ sender: UIButton?) {
        print("tapped button")
    }
    
    required init?(coder: NSCoder) {
        super.init(coder: coder)
    }
}

If you need to disambiguate between overloaded functions, use parenthesized expressions along with the as operator to make the #selector expression refer unambiguously to a specific overload.

Use Key Paths to Dynamically Access Objective-C Properties

In Objective-C, a key is a string that identifies a specific property of an object. A key path is a string of dot-separated keys that specifies a sequence of object properties to traverse. Keys and key paths are frequently used for key-value coding (KVC), a mechanism for indirectly accessing an object’s attributes and relationships using string identifiers.

You use the #keyPath string expression to create compiler-checked keys and key paths that can be used by KVC methods like value(forKey:) and value(forKeyPath:). The #keyPath string expression accepts chained method or property references. It also supports chaining through optional values within a chain, such as #keyPath(Person.bestFriend.name). Key paths created using the #keyPath string expression don’t pass type information about the properties or methods they reference to the APIs that accept key paths.

The example below defines a Person class, creates two instances of it, and uses several #keyPath string expressions to access properties and properties of those properties:

class Person: NSObject {
    @objc var name: String
    @objc var friends: [Person] = []
    @objc var bestFriend: Person? = nil
    
    init(name: String) {
        self.name = name
    }
}
 
let gabrielle = Person(name: "Gabrielle")
let jim = Person(name: "Jim")
let yuanyuan = Person(name: "Yuanyuan")
gabrielle.friends = [jim, yuanyuan]
gabrielle.bestFriend = yuanyuan
 
#keyPath(Person.name)
// "name"
gabrielle.value(forKey: #keyPath(Person.name))
// "Gabrielle"
#keyPath(Person.bestFriend.name)
// "bestFriend.name"
gabrielle.value(forKeyPath: #keyPath(Person.bestFriend.name))
// "Yuanyuan"
#keyPath(Person.friends.name)
// "friends.name"
gabrielle.value(forKeyPath: #keyPath(Person.friends.name))
// ["Yuanyuan", "Jim"]

See Also

Language Interoperability

Objective-C and C Code Customization

Apply macros to your Objective-C APIs to customize how they're imported into Swift.

Migrating Your Objective-C Code to Swift

Learn the recommended steps to migrate your code.

Cocoa Design Patterns

Adopt and interoperate with Cocoa design patterns in your Swift apps.

Handling Dynamically Typed Methods and Objects in Swift

Cast instances of the Objective-C id type to a specific Swift type.

Imported C and Objective-C APIs

Use native Swift syntax to interoperate with types and functions in C and Objective-C.