Swift from Scratch: A Complete Guide (Part 3)

Generics

Example

func findMaximum(_ a: T, _ b: T) -> T {
return a > b ? a : b
}

// Usage
let maxInt = findMaximum(10, 20) // Works with Int
print("Maximum Int: (maxInt)") // Output: 20

let maxDouble = findMaximum(3.5, 7.8) // Works with Double
print("Maximum Double: (maxDouble)") // Output: 7.8

let maxString = findMaximum("Apple", "Banana") // Works with String
print("Maximum String: (maxString)") // Output: Banana

Benefits of Generics:

Higher Order Function

Function as Parameter (Input)

func operateOnNumbers(_ a: Int, _ b: Int, using operation: (Int, Int) -> Int) -> Int {
    return operation(a, b)
}

Example 2: Function as Return Value (Output)

func makeMultiplier(by factor: Int) -> (Int) -> Int {
    return { number in
        return number * factor
    }
}

// Example usage:
let double = makeMultiplier(by: 2)
print(double(5)) // Output: 10

let triple = makeMultiplier(by: 3)
print(triple(5)) // Output: 15

map

let numbers = [1, 2, 3, 4, 5]

// Using map to square each number
let squaredNumbers = numbers.map { $0 * $0 }
print("Squared Numbers: \(squaredNumbers)") // Output: [1, 4, 9, 16, 25]

filter

let numbers = [1, 2, 3, 4, 5]

// Using filter to get even numbers
let evenNumbers = numbers.filter { $0 % 2 == 0 }
print("Even Numbers: \(evenNumbers)") // Output: [2, 4]

reduce

let numbers = [1, 2, 3, 4, 5]

// Using reduce to calculate sum
let sum = numbers.reduce(0) { $0 + $1 }
print("Sum: \(sum)") // Output: 15

Benefit of Higher Order Function

Memory Management

How does ARC work?

Strong, Weak, aur Unowned References

Strong Reference:

var person1 = Person(name: "John") // Reference count: 1
var person2 = person1             // Reference count: 2
person1 = nil                     // Reference count: 1

Weak Reference:

class Person {
    let name: String
    init(name: String) {
        self.name = name
    }
}

class Apartment {
    weak var tenant: Person? // Weak reference
}

var john: Person? = Person(name: "John")
var flat = Apartment()
flat.tenant = john
john = nil // Object deallocated kyunki weak reference ne object hold nahi kiya

Unowned Reference:

class CreditCard {
    unowned let owner: Person // Unowned reference
    init(owner: Person) {
        self.owner = owner
    }
}

var john: Person? = Person(name: "John")
var card = CreditCard(owner: john!)
john = nil // Card ka owner access karne ki koshish karoge to crash hoga

Memory Management Tips in Swift

class ViewController {
    var name = "Hello"
    func printName() {
        DispatchQueue.global().async { [weak self] in
            print(self?.name ?? "No Name")
        }
    }
}

Conclusion

Collection Type

Array

Create an Array

// Empty array
var numbers: [Int] = []

// Array with initial values
var fruits: [String] = ["Apple", "Banana", "Mango"]

// Type inference
var cities = ["Delhi", "Mumbai", "Kolkata"]

Access and Modify Elements

print(fruits[0]) // Output: Apple

fruits.append("Grapes") // Add a new element
fruits[1] = "Orange"    // Update element at index 1
print(fruits) // Output: ["Apple", "Orange", "Mango", "Grapes"]

Other Useful Operations

print(fruits.count)       // Number of elements
print(fruits.isEmpty)     // Check if array is empty
fruits.remove(at: 2)      // Remove element at index 2
print(fruits)             // Output: ["Apple", "Orange", "Grapes"]

Set

Create a Set

// Empty set
var numbers: Set<Int> = []

// Set with initial values
var fruits: Set<String> = ["Apple", "Banana", "Mango", "Apple"]
print(fruits) // Output: ["Mango", "Banana", "Apple"] (Order not fixed, duplicates removed)

Add and Remove Elements.

fruits.insert("Grapes")  // Add a new element
fruits.remove("Banana")  // Remove an element
print(fruits)            // Output: ["Mango", "Grapes", "Apple"]

Loop Through Set

for fruit in fruits {
    print(fruit)
}
// Output: Random order

Set Operations

let oddNumbers: Set = [1, 3, 5, 7]
let evenNumbers: Set = [2, 4, 6, 8]
let primeNumbers: Set = [2, 3, 5, 7]

// Union: Combine all elements
print(oddNumbers.union(evenNumbers)) // Output: [1, 2, 3, 4, 5, 6, 7, 8]

// Intersection: Common elements
print(oddNumbers.intersection(primeNumbers)) // Output: [3, 5, 7]

// Difference: Elements not in the other set
print(oddNumbers.subtracting(primeNumbers)) // Output: [1]

Dictionary

Create a Dictionary

// Empty dictionary
var students: [Int: String] = [:]

// Dictionary with initial values
var capitals: [String: String] = ["India": "Delhi", "USA": "Washington", "Japan": "Tokyo"]

Access and Modify Elements

Remove an Element

capitals["Japan"] = nil
print(capitals) // Output: ["USA": "Washington", "India": "New Delhi", "UK": "London"]

Loop Through Dictionary

for (country, capital) in capitals {
    print("\(country): \(capital)")
}
// Output:
// USA: Washington
// India: New Delhi
// UK: London

Struct and Class

Struct Example in Swift:

struct Point {
    var x: Int
    var y: Int
    
    func description() -> String {
        return "(\(x), \(y))"
    }
}

// Struct ka object create karte hain
var point1 = Point(x: 5, y: 10)
print(point1.description())  // Output: (5, 10)

// point1 ko copy karte hain
var point2 = point1
point2.x = 20
print(point1.description())  // Output: (5, 10)
print(point2.description())  // Output: (20, 10)

Class Example in Swift:

class Car {
    var model: String
    
    init(model: String) {
        self.model = model
    }
    
    func description() -> String {
        return "Car model is \(model)"
    }
}

// Class ka object create karte hain
var car1 = Car(model: "Tesla")
print(car1.description())  // Output: Car model is Tesla

// car1 ka reference car2 mein assign karte hain
var car2 = car1
car2.model = "BMW"
print(car1.description())  // Output: Car model is BMW
print(car2.description())  // Output: Car model is BMW

When to Use Structs vs Classes?

Additional Concepts:

Inheritance in Classes:

class Animal {
    var name: String
    init(name: String) {
        self.name = name
    }
    
    func speak() {
        print("\(name) makes a sound")
    }
}

class Dog: Animal {
    func fetch() {
        print("\(name) is fetching the ball!")
    }
}

let myDog = Dog(name: "Buddy")
myDog.speak()  // Output: Buddy makes a sound
myDog.fetch()  // Output: Buddy is fetching the ball!

Deinitializers in Classes:

class House {
    var address: String
    
    init(address: String) {
        self.address = address
    }
    
    deinit {
        print("\(address) ka memory release ho gaya hai.")
    }
}

var house1: House? = House(address: "123 Street")
house1 = nil  // Output: 123 Street ka memory release ho gaya hai.

Conclusion

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *