What is the difference between static and class members in Swift?
TL;DR
static and class both create members that belong to the type, not to an instance.
static cannot be overridden. It works in structs, enums, classes, actors and protocols.
class can be overridden by subclasses. It works only in classes, and only for methods and computed properties.
Type members in general
struct MathUtils {
static let pi = 3.14159
static func square(_ x: Double) -> Double { x * x }
}
MathUtils.square(MathUtils.pi) // call on the type, no instanceYou use them for constants, factory methods, shared instances and helpers.
static vs class in a class
class Animal {
static func kingdom() -> String { "Animalia" } // cannot override
class func sound() -> String { "..." } // can override
class var legs: Int { 4 } // computed, can override
}
class Bird: Animal {
override class func sound() -> String { "Tweet" }
override class var legs: Int { 2 }
// override static func kingdom() ... // error: cannot override static method
}
Bird.sound() // "Tweet"
Bird.legs // 2Side-by-side
static | class | |
|---|---|---|
| Works in | struct, enum, class, actor, protocol | class only |
| Overridable | No | Yes |
| Stored properties | Yes (static let, static var) | No |
| Computed properties | Yes | Yes |
| Dispatch | Static (direct) | Dynamic (vtable) |
In a class, static is the same as final class.
Why no class stored properties?
class Config {
// class var timeout = 30 // error: class stored properties not supported
static var timeout = 30 // OK
}A stored type property has one storage location for the whole program. Overriding it per subclass would need separate storage, so Swift does not allow it. Use a class var computed property if subclasses must return different values.
Overriding class with static
A subclass can override a class member with static. This stops further overrides.
class Base {
class func name() -> String { "Base" }
}
class Child: Base {
override static func name() -> String { "Child" } // final from here
}
// class GrandChild: Child {
// override class func name() ... // error
// }In protocols, always static
Protocols use static for type requirements. A class can satisfy it with class to allow overrides.
protocol Factory {
static func make() -> Self
}
class Vehicle: Factory {
required init() { }
class func make() -> Self { self.init() }
}
struct Point: Factory {
static func make() -> Point { Point() }
}Static stored properties are lazy and thread-safe
final class ImageCache {
static let shared = ImageCache()
private init() { }
}shared is created on first access. Swift guarantees it is created only once, even with many threads. This is the common singleton pattern.
In Swift 6 language mode, a static var is global mutable state. The compiler reports it as unsafe unless it is isolated (for example @MainActor), or you change it to a let of a Sendable type.
enum AppState {
@MainActor static var launchCount = 0 // OK in Swift 6
static let apiVersion = "v2" // OK: immutable and Sendable
}When to use which
- Use
staticby default. It is clearer and a little faster. - Use
classonly when you really want subclasses to change the behavior. - In
finalclasses, there is no difference, so usestatic.
Common follow-up questions
- Can
selfbe used inside a static method? Yes. Inside a type method,selfis the type itself, not an instance. - Is
Selfdifferent fromself?Self(capital) is the current type. In a class method it can be the subclass.selfin a type method is the metatype value. - Can an instance method call a static method without the type name? No. You write
Self.helper()orTypeName.helper(). - Are
staticproperties stored per subclass? No. There is one storage for the class and all subclasses. - Can extensions add
staticstored properties? Yes. Extensions cannot add instance stored properties, but static stored properties are fine.