- August 28, 2025
- Mins Read
In Swift, structures (struct
) and classes (class
) are the two primary building blocks for creating your own data types. Both let you encapsulate related data (properties) and behavior (methods) under a single, coherent type. Use them to model domain concepts—points in a game world, user profiles, network responses, and more.
struct UserProfile {
var username: String
var age: Int
func greet() {
print("Hi, I'm \(username), \(age) years old.")
}
}
class GameCharacter {
var name: String
var health: Int
init(name: String, health: Int) {
self.name = name
self.health = health
}
func takeDamage(_ amount: Int) {
health -= amount
print("\(name) took \(amount) damage, health is now \(health).")
}
}
Feature | Structure (Value Type) | Class (Reference Type) |
---|---|---|
Memory Semantics | Copied on assignment—each variable has its own independent copy. | Shared reference—multiple variables can point to the same instance. |
Inheritance | Cannot inherit from other types. | Supports single inheritance; can subclass and override behavior. |
Deinitializers | No deinitializer; cleanup isn’t necessary since values go out of scope. | Can implement deinit to run code when an instance is deallocated. |
Type Casting | No runtime casting; cannot use is /as to check or convert. |
Can check & downcast with is , as? , as! . |
Mutability Control | Mark with var to allow mutation; let instances are entirely immutable (all var properties become read-only). |
Even a let class instance can have its var properties changed; let only prevents rebinding. |
Use Case Guidance | Best for lightweight, small data types without shared mutable state (points, colors, simple data containers). | Ideal when identity matters or you need shared, mutable state and inheritance hierarchies (view controllers, data managers, delegates). |
struct MyStruct {
// Stored properties
var text: String
let count: Int
// Computed property
var isEmpty: Bool { text.isEmpty }
// Method
func describe() -> String {
return "‘\(text)’ has \(count) items."
}
// Mutating method (modifies self)
mutating func update(text newText: String) {
text = newText
}
}
let
for constants, var
for variables.mutating
methods are required when a method changes self
or its properties.class MyClass {
// Stored properties
var title: String
let maxCount: Int
// Initializer
init(title: String, maxCount: Int) {
self.title = title
self.maxCount = maxCount
}
// Computed property
var isFull: Bool { title.count >= maxCount }
// Method
func describe() -> String {
return "‘\(title)’ (max \(maxCount))"
}
// Deinitializer
deinit {
print("MyClass titled ‘\(title)’ is being deallocated")
}
}
init
) must set all stored properties before self
is used.deinit
runs just before the instance is deallocated (no arguments, no return).var a = MyStruct(text: "Hello", count: 5)
var b = a // b is a copy of a
b.update(text: "Bye")
print(a.text) // "Hello"
print(b.text) // "Bye"
b
doesn’t affect a
; each has its own storage.let obj1 = MyClass(title: "Level 1", maxCount: 3)
let obj2 = obj1 // obj2 references the same instance
obj2.title = "Boss"
print(obj1.title) // "Boss"
obj2
affects obj1
; they share identity.struct
when:
class
when:
deinit
for cleanup (e.g., removing observers).Both structures and classes expose their data via properties, accessed with dot syntax.
struct Rectangle {
var width: Double
var height: Double
// Computed property
var area: Double {
return width * height
}
}
var rect = Rectangle(width: 10, height: 5)
print(rect.width) // 10
print(rect.height) // 5
print(rect.area) // 50
width
, height
) hold data.area
) calculate on-the-fly.rect.width = 12
(if var
), but if rect
were declared with let
, you couldn’t mutate any of its properties.Classes work the same way:
class Circle {
var radius: Double
var circumference: Double { 2 * .pi * radius }
init(radius: Double) {
self.radius = radius
}
}
let c = Circle(radius: 3)
print(c.circumference) // ~18.85
c.radius = 5 // OK, even though c is a let-constant
Swift automatically generates a memberwise initializer for structs that don’t define any custom initializers. This saves you from writing boilerplate.
struct Point {
var x: Double
var y: Double
}
let p = Point(x: 2.0, y: 4.5)
Point(x:y:)
“for free” as long as you don’t write your own init
.struct Color {
var red: Double = 0
var green: Double = 0
var blue: Double = 0
}
let black = Color() // uses all defaults
let magenta = Color(red: 1, blue: 1)
init()
).struct User {
var name: String
}
var u1 = User(name: "Alice")
var u2 = u1 // copy made here
u2.name = "Bob"
print(u1.name) // "Alice"
print(u2.name) // "Bob"
u2
never affect u1
.enum Status {
case active, inactive
}
var s1 = Status.active
var s2 = s1
s2 = .inactive
print(s1) // .active
Value types are ideal for small, immutable pieces of data (points, ranges, settings).
class Player {
var score: Int = 0
}
let p1 = Player()
let p2 = p1 // both refer to the same Player
p2.score = 10
print(p1.score) // 10
Swift provides two operators to compare whether two references point to exactly the same class instance:
===
returns true
if both sides refer to the identical object.!==
is the inverse.let a = Player()
let b = Player()
let c = a
print(a === b) // false: different instances
print(a === c) // true: c is the same instance as a
print(a !== b) // true
This package provides you with an easy way to show tooltips over any SwiftUI view, since Apple does not provide ...
SimpleToast is a simple, lightweight, flexible and easy to use library to show toasts / popup notifications inside iOS or ...
Create Toast Views with Minimal Effort in SwiftUI Using SSToastMessage. SSToastMessage enables you to effortlessly add toast notifications, alerts, and ...