SwiftQARandom

What is identity in Swift, and when do you use ===?

In Swift, identity is the idea that two references might point to the same object in memory, versus two objects merely having the same value. It only applies to reference types (classes) — value types like structs and enums don’t have identity, only equality, because each copy is independent.

Identity operators: === and !==

Swift gives you the identity operators === and !== to check whether two references point to the same instance:

class Person {
    var name: String
    init(name: String) { self.name = name }
}

let a = Person(name: "Alice")
let b = Person(name: "Alice")
let c = a

a === b  // false — different instances, even though name matches
a === c  // true — c points to the same instance as a

Identity vs. equality

This is different from ==, which checks equality (whether two things represent the same value) and requires conforming to Equatable. Two Person instances could be == if you defined equality based on name, while still being !== because they’re separate objects in memory. For classes, if you don’t implement Equatable yourself, == isn’t available by default — === works out of the box on any class because it’s just comparing memory addresses.

Checks Operator Applies to
Equality Do these represent the same value? == Any Equatable type
Identity Are these literally the same object? === Reference types (classes) only

When identity is used

Mutation tracking — since classes are reference types, if a === c, mutating a.name also changes what c sees, because they’re the same object. Checking identity helps you reason about or guard against that kind of shared-state surprise.

Avoiding redundant work — e.g., in a didSet or update method, checking if self === sender { return } to avoid reacting to your own notification, a common pattern in delegate/observer setups.

Caching and deduplication — checking whether an object you’re about to insert into a cache or collection is literally the same instance already there, not just an equal-looking one.

Delegate patterns — verifying that a callback came from the delegate you expect: if delegate === self.expectedDelegate.

Using objects as dictionary/set keys by identity rather than value — Swift’s ObjectIdentifier wraps a class instance’s identity so it can be hashed and compared, useful when you want a Set or Dictionary keyed by “which specific object” rather than “which equal-valued object.”

Memory management debugging — confirming whether a weak reference still points to the original instance, or checking for accidental retain-cycle-related duplication.

Mental model

A useful mental model: == asks “do these represent the same value?” while === asks “are these literally the same object?” For structs, only the first question even makes sense, since there’s no shared instance to point to.