Passing arguments to selector in Swift
Interview Questions practice on Codemia
Over 8,000 real interview questions from top companies, searchable by company and role.
Selectors are a bridge between Swift and the Objective-C runtime, used heavily in UIKit's target-action pattern. When you add an action to a button or set up a timer, you reference a method by its selector. A common question that trips up developers is how to pass custom arguments through a selector, since the #selector syntax does not support arbitrary parameters directly. Understanding this limitation and the available workarounds is essential for writing clean UIKit code.
How Selectors Work
A selector is essentially a name that identifies a method at runtime. You create one using the #selector expression, which the compiler verifies at build time. The target-action pattern used by UIControl subclasses like UIButton only supports two method signatures for action methods: one with no parameters and one that receives the sender.
Notice that both methods are marked @objc. This is required because selectors rely on the Objective-C runtime, and Swift methods are not exposed to that runtime by default.
Why You Cannot Pass Custom Arguments Directly
The #selector expression only captures a method name. It does not capture or forward arguments. The target-action mechanism is designed so that UIKit itself calls your method, passing either nothing or the sender object. There is no built-in slot for additional data.
This means the following will not compile:
Workaround 1: Use the Tag Property
The simplest approach for passing an integer identifier is to use the tag property that every UIView has:
This works well when you have a list of buttons (for example, in a loop) and each button needs to carry a simple numeric identifier.
Workaround 2: Subclass UIButton to Hold Extra Data
When you need to pass more than a single integer, create a custom button subclass with additional stored properties:
This keeps the data directly on the sender, so the action method has full access without needing external lookups.
Workaround 3: Use a Closure-Based Approach
Starting with iOS 14, UIAction lets you attach a closure directly to a control, bypassing selectors entirely:
Because closures capture their surrounding scope, you can reference any local variable without needing tags or subclasses. This is the most modern and flexible approach.
Workaround 4: Use objc_setAssociatedObject
For cases where you cannot subclass the control, Objective-C associated objects let you attach arbitrary data to any NSObject:
Common Pitfalls
- Forgetting the
@objcattribute. Every method referenced by#selectormust be marked@objc, or the compiler will produce an error. If your class does not inherit fromNSObject, you also need to make it anNSObjectsubclass. - Over-relying on
tagfor complex data. Thetagproperty is only anInt. Trying to encode multiple values into a single integer leads to fragile code that is hard to maintain. - Using selectors in SwiftUI. SwiftUI uses closures and the Combine framework for event handling, not selectors. Attempting to use
#selectorin a SwiftUI view is a design mismatch. - Retaining self in closure-based actions. When using
UIActionclosures, capturingselfstrongly can create retain cycles if the button is owned by the same view controller. Use[weak self]when needed. - Misspelling the method signature. Before
#selectorwas introduced in Swift 2.2, selectors were string-based and typos caused silent runtime crashes. Always prefer the compiler-checked#selectorsyntax overSelector("methodName").
Summary
- Selectors in Swift reference method names at runtime and support either zero parameters or a single sender parameter.
- You cannot pass custom arguments through
#selectordirectly because the target-action pattern does not support it. - Use
UIView.tagfor simple integer identifiers, aUIButtonsubclass for richer data, orUIActionclosures (iOS 14 and later) to avoid selectors altogether. - Always mark selector-referenced methods with
@objcand ensure the class inherits fromNSObject. - In modern UIKit code, prefer closure-based
UIActionover selectors for cleaner, more flexible event handling.
Related reading
- Passing data between a fragment and its container activity
- Passing data between view controllers
- Passing data between view controllers
- Passing data between view controllers
- Passing enum or object through an intent the best solution
- Passing parameters to addTargetactionforControlEvents
- Passing through touches to UIViews underneath
- Password hint font in Android
.png&w=3840&q=75)
Tackling System Design Interview Problems
A short course that equips you with the skills to approach system design interviews methodically.
Start the free courseTrack what you have practised
A free account saves your progress, solutions and study plan across every problem on Codemia.
Interview Questions practice on Codemia
Over 8,000 real interview questions from top companies, searchable by company and role.