@selector() in Swift: A Complete Guide for ObjC Compatibility

Online Python Trainer for Beginners

Learn Python easily without overwhelming theory. Solve practical tasks with automatic checking, get hints in Russian, and write code directly in your browser — no installation required.

Start Course

What is @selector() in Swift and why is it needed?



If you've ever worked with Objective-C or encountered legacy code, you've probably heard of the magical @selector() construct. In Swift, it has transformed into #selector, but the essence remains the same: it's a bridge between Swift's static typing and the dynamic nature of the Objective-C runtime.



Imagine you need to pass a reference to a method as an argument. For example, to handle a button press or subscribe to notifications. In Swift, we are used to using closures, but Apple's libraries (UIKit, AppKit, Foundation) still rely on the good old selector mechanism. This is where @selector() in Swift becomes an indispensable tool.



In this guide, we'll cover:

  • How to properly declare selectors in modern Swift
  • Common mistakes and how to avoid them
  • Real-world examples from iOS development
  • When to use #selector and when to use alternatives


From @selector() to #selector: The Evolution of Syntax



In Objective-C, a selector looks like this:

[@selector(buttonTapped:)]


In Swift 2.0, the #selector construct appeared and became the standard. Here's what it looks like now:

#selector(MyClass.buttonTapped(_:))


The key difference: #selector in Swift is checked by the compiler. If you misspell the method name or pass an incorrect signature, the compiler will throw an error. This is a huge advantage over Objective-C, where a selector is just a string and the error only surfaces at runtime.



Rules for Declaring Methods for #selector



The method you pass to #selector must be:

  • Accessible from Objective-C — marked with the @objc attribute
  • Not private (or marked as @objc private)
  • Signature-compatible with what the calling side expects


Example of a correct declaration:

class ViewController: UIViewController {    @objc func buttonTapped(_ sender: UIButton) {        print("Button tapped!")    }        override func viewDidLoad() {        super.viewDidLoad()        let button = UIButton(type: .system)        button.addTarget(self, action: #selector(buttonTapped(_:)), for: .touchUpInside)    }}


Note the @objc before the method. Without it, the compiler will not allow using #selector.



@selector() Swift: Practical Examples



1. Target-Action: Buttons and Gestures



The most common use case for #selector is binding actions to UI elements:



class ProfileViewController: UIViewController {        @objc private func avatarTapped(_ gesture: UITapGestureRecognizer) {        print("Avatar tapped")    }        @objc private func settingsButtonPressed() {        print("Open settings")    }        override func viewDidLoad() {        super.viewDidLoad()                // Gesture        let tapGesture = UITapGestureRecognizer(target: self, action: #selector(avatarTapped(_:)))        avatarImageView.addGestureRecognizer(tapGesture)                // Button        settingsButton.addTarget(self, action: #selector(settingsButtonPressed), for: .touchUpInside)    }}


Remember: if the method accepts a parameter (e.g., UITapGestureRecognizer), you must specify _ in the selector signature: #selector(avatarTapped(_:)).



2. PerformSelector and Delayed Calls



Sometimes you need to call a method dynamically, especially when working with KVO or timers:



class TimerManager {    @objc func fireTimer() {                

Blogs

Book Recommendations