Swift is Apple's programming language that combines the power of Objective-C with the safety of modern languages. Unlike many other languages, Swift offers unique constructs: value types with automatic copying, Actors with compiler-level isolation, Property Wrappers for reusing property logic, and Protocol Oriented Programming as an alternative to classical inheritance. According to Apple Swift Documentation, these features make code safer and more performant.
Key Takeaways
In Swift, struct is a value type, while class is a reference type. This fundamental difference determines behavior during assignment, passing to functions, and memory management. Struct is copied entirely on each assignment, class is passed by reference — only the pointer to the heap object is copied.
Struct automatically implements value semantics — each instance is independent. Mutation of a struct property is only possible through var, and methods that modify properties must be marked mutating. Struct does not support inheritance but can conform to protocols. Swift's standard library uses struct for String, Array, Dictionary, Int, Bool — all fundamental types are value types.
struct User {
let id: Int
var name: String
mutating func updateName(_ newName: String) {
name = newName
}
}
var user1 = User(id: 1, name: "Alice")
var user2 = user1
user2.updateName("Bob")
// user1.name === "Alice", user2.name === "Bob"
// Full copy — independent instances
Class is stored in the heap and supports reference equality. Multiple variables can reference the same object, changes through one reference are visible through all others. Class supports inheritance, allows method overriding (override), has deinit for resource cleanup. In Swift, class is used less frequently than struct — Apple recommends starting with struct and switching to class only when inheritance or reference semantics are needed.
class Car {
let model: String
var speed: Int
init(model: String, speed: Int) {
self.model = model
self.speed = speed
}
func accelerate(_ amount: Int) {
speed += amount
}
}
let car1 = Car(model: "Tesla", speed: 0)
let car2 = car1
car2.accelerate(50)
// car1.speed === 50, car2.speed === 50
// Same reference — changes visible everywhere
The choice between struct and class depends on data semantics. For configurations, data models, and states use struct — copying is safer and more predictable. For objects with identity (user session, database connection) and when inheritance is needed, use class.
Actor is a reference type that protects its mutable state from concurrent access. The Swift compiler guarantees that actor variables can only be accessed from within the same actor context — any external access causes a compilation error. This prevents data races at the language level without manual locks.
All actor properties and methods are isolated by default. Calling an actor method from outside requires await — Swift switches execution to the actor and back. Actor synchronizes access sequentially: requests from different tasks are queued. This ensures consistent state inside the actor. Non-isolated methods (nonisolated) can be called without await but cannot access mutable properties.
actor BankAccount {
private var balance: Double
init(initialBalance: Double) {
balance = initialBalance
}
func deposit(amount: Double) {
balance += amount
}
func withdraw(amount: Double) throws {
guard balance >= amount else {
throw BankError.insufficientFunds
}
balance -= amount
}
nonisolated func accountInfo() -> String {
return "Bank Account"
}
}
let account = BankAccount(initialBalance: 1000)
await account.deposit(amount: 500)
// balance = 1500 — atomic, no race condition
Actor is useful for state managers, caches, and network services where multiple tasks concurrently read and write data. Unlike manual synchronization via NSLock or DispatchQueue, actor is checked at compile time — it is impossible to make a mistake. Isolation errors appear at compile time, not at runtime.
Property Wrapper is an annotation that adds behavior to a property without changing its declaration. SwiftUI and Combine provide built-in wrappers for managing view state. The compiler generates code that wraps property access, adding observation, synchronization, or transformation logic.
@Published is used in classes conforming to ObservableObject to automatically publish changes. Combine subscribers receive notifications on each update. @State is local SwiftUI view state. SwiftUI automatically redraws the view when @State changes. @Binding creates a two-way connection between a parent and child view without owning the data.
import SwiftUI
import Combine
@main
struct CounterApp: App {
var body: some Scene {
WindowGroup {
ContentView()
}
}
}
class CounterViewModel: ObservableObject {
@Published var count: Int = 0
func increment() {
count += 1
}
}
struct ContentView: View {
@State private var greeting: String = "Hello"
@StateObject private var viewModel = CounterViewModel()
var body: some View {
VStack {
CounterDisplay(count: $viewModel.count)
Text(greeting)
Button("Increment", action: viewModel.increment)
}
}
}
struct CounterDisplay: View {
@Binding var count: Int
var body: some View {
Text("Count: \(count)")
}
}
Custom Property Wrappers are created using @propertyWrapper and a struct with a wrappedValue field. This allows reusing logic: validation, normalization, UserDefaults storage. Property Wrappers significantly reduce boilerplate code and make developer intent explicit through annotation.
@propertyWrapper
struct Clamped<T: Comparable> {
private var value: T
let range: ClosedRange<T>
init(wrappedValue: T, range: ClosedRange<T>) {
self.range = range
self.value = min(max(wrappedValue, range.lowerBound), range.upperBound)
}
var wrappedValue: T {
get { value }
set { value = min(max(newValue, range.lowerBound), range.upperBound) }
}
}
struct Settings {
@Clamped(range: 0...100) var volume: Int = 50
}
var s = Settings()
s.volume = 150
// s.volume === 100 — value automatically clamped
Generics is a powerful Swift mechanism for writing flexible code without losing type safety. Generic functions and types work with any type that meets constraints. Protocol Oriented Programming (POP) is a Swift paradigm where protocol + extension replace classical class inheritance, providing behavior composition.
Swift allows constraining generic parameters with protocols (where clauses). Protocol with associated type is the generic equivalent for protocols: the concrete type is determined at conforming time. This is the foundation for type-safe collections and algorithms. Swift's standard library actively uses generics: Array, Dictionary, Optional — all are generic types.
protocol Cacheable {
associatedtype Key: Hashable
associatedtype Value
func get(_ key: Key) -> Value?
mutating func set(_ value: Value, for key: Key)
}
struct MemoryCache<K: Hashable, V>: Cacheable {
private var storage: [K: V] = [:]
typealias Key = K
typealias Value = V
func get(_ key: K) -> V? {
return storage[key]
}
mutating func set(_ value: V, for key: K) {
storage[key] = value
}
}
func firstMatch<T: Equatable>(in array: [T], target: T) -> Int? {
for (index, item) in array.enumerated() {
if item == target {
return index
}
}
return nil
}
let numbers = [10, 20, 30, 40]
let index = firstMatch(in: numbers, target: 30)
// index === 2 — one generic method for all Equatable types
Protocol extension is a key POP mechanism. An extension can provide default implementations for protocol methods. Types conforming to the protocol get this implementation for free and can override it if needed. This allows building behavior hierarchies without class inheritance — an alternative to multiple inheritance, which is not available in Swift.
protocol Drivable {
var speed: Double { get set }
func drive()
}
extension Drivable {
func drive() {
if speed > 0 {
print("Driving at \(speed) km/h")
}
}
}
struct Bicycle: Drivable {
var speed: Double = 15
}
struct Plane: Drivable {
var speed: Double = 900
func drive() {
print("Flying at \(speed) km/h")
}
}
let bike = Bicycle()
bike.drive() // "Driving at 15.0 km/h" — default
let plane = Plane()
plane.drive() // "Flying at 900.0 km/h" — overridden
POP with extension enables composition through multiple protocols — a type can conform to several protocols, getting their implementations. This is more flexible than single class inheritance where the entire hierarchy is fixed. Swift's standard library is built on POP: CustomStringConvertible, Equatable, Hashable, Codable — all are protocols with extensions.
Enum in Swift is a significantly more powerful construct than in other languages. Each case can have associated values — an arbitrary set of data of any type. Combined with extension and pattern matching, enum becomes the foundation for modeling states, operation results, and finite state machines.
Associated values allow each case to store unique data. For example, the loading case contains no data, success contains the result, failure contains an error. Pattern matching via switch extracts associated values and handles each case. The compiler checks exhaustiveness (exhaustive switch) — this eliminates forgotten states.
enum NetworkResult<T> {
case loading
case success(T)
case failure(Error)
}
enum MediaFile {
case image(url: URL, width: Int, height: Int)
case video(url: URL, duration: Double)
case audio(url: URL, bitrate: Int)
}
func handle(_ result: NetworkResult<String>) {
switch result {
case .loading:
print("Loading...")
case .success(let data):
print("Received: \(data)")
case .failure(let error):
print("Error: \(error.localizedDescription)")
}
}
let file = MediaFile.video(url: URL(string: "https://example.com/video.mp4")!, duration: 120)
if case .video(let url, let duration) = file {
print("Video \(url) duration \(duration)s")
}
Swift allows adding methods, computed properties, and protocol conformance via extensions for enums. This does not require changing the original declaration — code remains clean and modular. Methods in extensions can work with associated values, compute derived data, and implement business logic.
extension MediaFile {
var fileName: String {
switch self {
case .image(let url, _, _),
.video(let url, _),
.audio(let url, _):
return url.lastPathComponent
}
}
var description: String {
switch self {
case .image(_, let w, let h):
return "Image \(w)x\(h)"
case .video(_, let d):
return "Video \(d)s"
case .audio(_, let b):
return "Audio \(b) kbps"
}
}
}
extension MediaFile: Equatable {
static func == (lhs: MediaFile, rhs: MediaFile) -> Bool {
return lhs.fileName == rhs.fileName
}
}
let files: [MediaFile] = [file]
files.forEach { print($0.description) }
// "Video 120.0s"
Enum with associated values + extension is the replacement for sealed classes from Kotlin or discriminated unions from other languages. Swift uses this combination for Result (a standard type in the standard library), Optional (Optional is an enum with .none and .some) and state handling in SwiftUI. Pattern matching guarantees all states are handled — runtime errors are impossible.
Frequently Asked Questions
Struct — value type, copied on assignment, does not support inheritance. Class — reference type, passed by reference, supports inheritance, deinit and identity check (===). Apple recommends starting with struct and switching to class only when reference semantics are needed.
Actor — thread-safe reference type. The compiler prevents concurrent access to mutable state from different contexts. Use Actor for state managers, caches, and services accessed by multiple tasks. Calling actor methods requires await.
Main ones: @State — local view state; @Binding — data connection without ownership; @Published — publishes changes in ObservableObject; @StateObject — owns ObservableObject; @EnvironmentObject — dependency from environment. Custom wrappers are created via @propertyWrapper.
POP — a paradigm where protocol + extension define behavior instead of class inheritance. A type conforms to multiple protocols, getting their implementations for free. This is composition over inheritance — more flexible and safer. Swift's standard library (Equatable, Codable) is built on POP.
Enum in Swift supports associated values — each case can store arbitrary data of different types. Combined with pattern matching (switch), this provides a powerful model for states, errors, and Domain-Driven Design. Optional and Result are standard Swift enums with associated values.
Summary
We will develop a mobile application turnkey
IT Sectr creates iOS and Android applications for startups and businesses since 2017. We will advise you and propose the best solution.