Selectors: Objective-C's Function Pointers in Swift

A selector is a lightweight name for a method, not a direct pointer. Swift uses it to call Objective-C code dynamically at runtime. It's common in UIKit for target-action patterns, like button taps. The footgun: forgetting `@objc` causes a runtime crash.
WHY IT EXISTS: Swift needs a way to interact with the vast number of existing Apple frameworks written in Objective-C. These frameworks rely on a dynamic runtime for features like the target-action pattern. Selectors are the bridge that allows static Swift code to call these dynamic Objective-C APIs.
THE MENTAL MODEL: A selector is a name, not a direct function pointer. Imagine it's a person's name written on a note. To deliver a message, you don't go to a pre-defined address; you ask a central directory (the Objective-C runtime) to find the person with that name. This lookup happens when the code runs, making it dynamic but also riskier than a direct, compile-time checked call.
HOW IT WORKS: In Swift, you create a selector with the #selector() syntax, like #selector(myButtonTapped). The Swift compiler verifies that a method with that name exists in the current scope. However, for the Objective-C runtime to find it later, the method itself must be exposed using the @objc attribute. This attribute tells the compiler to generate the necessary metadata that the Objective-C runtime needs to discover the method by its string name.
WHEN TO USE IT: You must use selectors when an API from an Objective-C framework requires one. Three common places are: first, the target-action pattern in UIKit and AppKit, such as for UIButton taps or UIGestureRecognizer events; second, creating a Timer that fires repeatedly; and third, registering for notifications with NotificationCenter.
WHEN NOT TO USE IT: For any new, pure-Swift code, avoid selectors. Prefer modern Swift patterns like closures or Combine publishers. Closures are type-safe, checked at compile time, and capture their context, which avoids the runtime risks and indirection associated with selectors. Only use selectors when interoperability with an older Objective-C API forces you to.
ONE CANONICAL EXAMPLE: The most common use is handling a button tap in UIKit. You create a button and tell it what to call when tapped using addTarget. The action parameter requires a selector, like myButton.addTarget(self, action: #selector(handleTap), for: .touchUpInside). The corresponding method, handleTap, must be marked @objc func handleTap() { ... }. If you forget the @objc attribute, your code will compile, but the app will crash with an "unrecognized selector sent to instance" error when you tap the button.
Read the original → developer.apple.com
Get five bites like this every day.
Tezvyn delivers a daily feed of 60-second tech bites with quizzes to lock in what you learn.