- 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 ...