Object-Oriented Programming
## Learning Objectives
- Understand classes and structures
- Master inheritance
- Work with protocols
- Learn initialization and deinitialization
## Classes vs Structures
### Structure (Value Type)
```swift
struct Person {
var name: String
var age: Int
func describe() {
print("\(name) is \(age) years old")
}
}
var person = Person(name: "Alice", age: 30)
person.describe()
```
### Class (Reference Type)
```swift
class Vehicle {
var brand: String
var speed: Int = 0
init(brand: String) {
self.brand = brand
}
func describe() {
print("\(brand) at \(speed) km/h")
}
}
let vehicle = Vehicle(brand: "Tesla")
```
### Key Differences
| Feature | Struct | Class |
|---------|--------|-------|
| Type | Value | Reference |
| Inheritance | No | Yes |
| Deinit | No | Yes |
| Multiple references | No (copied) | Yes (shared) |
### Value vs Reference
```swift
struct PointStruct {
var x: Int
var y: Int
}
var s1 = PointStruct(x: 1, y: 2)
var s2 = s1
s2.x = 10
print(s1.x) // 1 (unchanged - copy!)
class PointClass {
var x: Int
var y: Int
init(x: Int, y: Int) {
self.x = x
self.y = y
}
}
var c1 = PointClass(x: 1, y: 2)
var c2 = c1
c2.x = 10
print(c1.x) // 10 (changed - same reference!)
```
## Initialization
### Memberwise Init (Structures)
```swift
struct Point {
var x: Int
var y: Int
}
let point = Point(x: 5, y: 10)
```
### Custom Init (Classes)
```swift
class BankAccount {
var accountNumber: String
var balance: Double
init(accountNumber: String, initialBalance: Double) {
self.accountNumber = accountNumber
self.balance = initialBalance
}
convenience init() {
self.init(accountNumber: "000", initialBalance: 0)
}
}
```
### Property Initializers
```swift
class Circle {
var radius: Double
let pi: Double = 3.14159
init(radius: Double) {
self.radius = radius
}
var area: Double {
return pi * radius * radius
}
}
```
### Initializer Delegation
```swift
class Rectangle {
var width: Double
var height: Double
init(width: Double, height: Double) {
self.width = width
self.height = height
}
init(size: Double) {
self.init(width: size, height: size)
}
init() {
self.init(size: 0)
}
}
let rect = Rectangle(size: 10)
```
## Deinitialization
### deinit (Classes Only)
```swift
class FileHandler {
var fileName: String
init(fileName: String) {
self.fileName = fileName
print("Opening \(fileName)")
}
deinit {
print("Closing \(fileName)")
}
}
if true {
let handler = FileHandler(fileName: "data.txt")
}
// "Closing data.txt" printed when handler goes out of scope
```
## Inheritance
### Basic Inheritance
```swift
class Animal {
var name: String
init(name: String) {
self.name = name
}
func speak() {
print("...")
}
}
class Dog: Animal {
override func speak() {
print("Woof!")
}
}
class Cat: Animal {
override func speak() {
print("Meow!")
}
}
let dog = Dog(name: "Buddy")
dog.speak() // Woof!
```
### Override Methods
```swift
class Vehicle {
func description() -> String {
return "A vehicle"
}
}
class Car: Vehicle {
var wheels: Int = 4
override func description() -> String {
return "A car with \(wheels) wheels"
}
}
```
### Override Properties
```swift
class Person {
var name: String
var age: Int
var description: String {
return "\(name), \(age) years old"
}
init(name: String, age: Int) {
self.name = name
self.age = age
}
}
class Student: Person {
var grade: String = "A"
override var description: String {
return super.description + " (Grade: \(grade))"
}
}
```
### Final Classes
Prevent inheritance:
```swift
final class MathHelper {
static func square(_ n: Int) -> Int {
return n * n
}
}
// class AdvancedMath: MathHelper {} // Error!
```
## Access Control
### Access Levels
| Level | Class | Subclass | Module | anywhere |
|-------|-------|----------|--------|----------|
| private | Yes | No | No | No |
| fileprivate | Yes | No | Yes | No |
| internal | Yes | Yes | Yes | No |
| public | Yes | Yes | Yes | Yes |
| open | Yes | Yes | Yes | Yes |
### Examples
```swift
public class PublicClass {
private var secret: String = "hidden"
internal var name: String = "visible"
public var data: Int = 0
}
```
## Protocols
### Defining Protocols
```swift
protocol Drawable {
func draw()
var color: String { get set }
}
protocol Printable {
func printDescription()
}
```
### Conforming to Protocols
```swift
class Circle: Drawable {
var color: String
var radius: Double
init(color: String, radius: Double) {
self.color = color
self.radius = radius
}
func draw() {
print("Drawing circle with radius \(radius)")
}
}
```
### Protocol Inheritance
```swift
protocol Shape {
var area: Double { get }
}
protocol Printable {
func printDescription()
}
class Rectangle: Shape, Printable {
var width: Double
var height: Double
var area: Double {
return width * height
}
init(width: Double, height: Double) {
self.width = width
self.height = height
}
func printDescription() {
print("Rectangle: \(width) x \(height)")
}
}
```
### Protocol Extensions
```swift
protocol Summable {
var total: Int { get }
}
extension Summable where Self: Numeric {
var total: Int {
return 0
}
}
```
## Static and Class Members
### Static Properties
```swift
struct Counter {
static var count = 0
init() {
Counter.count += 1
}
}
let c1 = Counter()
let c2 = Counter()
print(Counter.count) // 2
```
### Class Properties
```swift
class Configuration {
class var defaultTimeout: Int {
return 30
}
}
print(Configuration.defaultTimeout) // 30
```
## Methods
### Instance Methods
```swift
class Counter {
var count: Int = 0
func increment() {
count += 1
}
func increment(by amount: Int) {
count += amount
}
func reset() {
count = 0
}
}
```
### Mutating Methods (Structures)
```swift
struct Point {
var x: Int
var y: Int
mutating func moveBy(dx: Int, dy: Int) {
x += dx
y += dy
}
}
var point = Point(x: 1, y: 2)
point.moveBy(dx: 3, dy: 4)
print(point) // Point(x: 4, y: 6)
```
## Properties
### Stored Properties
```swift
class Person {
var name: String
var age: Int
init(name: String, age: Int) {
self.name = name
self.age = age
}
}
```
### Computed Properties
```swift
struct Rectangle {
var width: Double
var height: Double
var area: Double {
return width * height
}
var perimeter: Double {
return 2 * (width + height)
}
}
```
### Property Observers
```swift
class ProgressTracker {
var progress: Double = 0 {
willSet {
print("Will set to \(newValue)")
}
didSet {
print("Did set from \(oldValue) to \(progress)")
}
}
}
```
### Lazy Properties
```swift
class DataImporter {
var fileName = "data.txt"
// Heavy initialization
}
class DataManager {
lazy var importer = DataImporter()
init() {
print("Manager initialized")
}
}
let manager = DataManager() // importer not created yet
print(manager.importer.fileName) // Now importer is created
```
## Summary
- Classes are reference types; structures are value types
- Classes support inheritance; structures do not
- Classes have deinit; structures do not
- Use `init` for initialization; `deinit` for cleanup
- Protocols define contracts; classes/structs conform
- Access control: private, fileprivate, internal, public, open
- Computed properties calculate values; stored properties hold values
- `mutating` keyword needed for struct methods that modify properties
- Lazy properties initialize on first access
- Property observers (willSet/didSet) respond to changes
Comments
Comments powered by Giscus
To enable comments, add your Giscus embed code here.
Learn more about Giscus →