tezvyn:

@objc: Swift's Bridge to Objective-C

AI-drafted, machine-checkedintermediate

@objc is the bridge badge that exposes Swift code to the Objective-C runtime so UIKit selectors and KVO work. You need it for target-action and Core Data. Forget it and you get a runtime crash, not a compiler error.

WHY IT EXISTS: Swift and Objective-C share a process but not a calling convention. The Objective-C runtime depends on message passing via selectors, dynamic method lookup, and the NSObject hierarchy. Swift defaults to static dispatch and vtable dispatch, and it does not automatically register methods with the Objective-C runtime. @objc exists to opt individual Swift declarations into that runtime so UIKit, Core Data, and notification selectors continue to function without forcing every Swift function to pay the overhead and binary cost of dynamic messaging.

THE MENTAL MODEL: Think of @objc as a visa stamp. Swift code lives in its own neighborhood with static types and aggressive performance optimizations. Objective-C lives in a dynamic message-passing city. When Swift code needs to cross into that city, or when the city needs to call back into Swift, the declaration needs a visa. Without the stamp, the border guard, which is the Objective-C runtime, simply does not recognize the traveler and refuses entry.

HOW IT WORKS: When you apply @objc to a method, property, or class, the Swift compiler generates an Objective-C compatible symbol and a selector mapping. It registers the declaration with the Objective-C runtime, enabling dynamic dispatch and message sending. You can also apply @objcMembers to a class to expose all eligible members automatically, though this is less common now. Starting with Swift 4, the compiler stopped inferring @objc in many contexts, so explicit annotation is usually required unless you override an Objective-C method or conform to an Objective-C protocol.

WHEN TO USE IT: Use @objc when you need Objective-C runtime features. This includes wiring UIKit target-action methods with selectors, observing properties with KVO, using Core Data NSManagedObject subclasses, overriding methods from an Objective-C base class, or exposing a Swift API to an Objective-C caller. If a protocol is defined in Objective-C and you implement it in Swift, the conforming methods often need the attribute so the runtime can construct the required method table.

WHEN NOT TO USE IT: Do not sprinkle @objc on pure Swift code that never interacts with Objective-C. Unnecessary use increases binary size by generating thunks and metadata, and it disables certain Swift optimizations like devirtualization and inlining. Avoid @objcMembers as a default; it exposes every eligible method and property, which bloats the interface, increases compile times, and can leak internals you intended to keep Swift-only.

ONE CANONICAL EXAMPLE: Imagine a view controller with a button. You write func handleTap and pass a selector to button.addTarget. Without @objc, the compiler may let the selector syntax pass, but at runtime the Objective-C runtime cannot find the method, and your app crashes with an unrecognized selector exception. Adding @objc func handleTap bridges the method so the runtime can call it when the user taps the button. This single missing attribute is one of the most common sources of runtime crashes in Swift UIKit code.

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.