•
Welcome to Part 5 of our Swift Programming Tutorial series! Now we will take you a little further from the basic understanding of Swift, and explore some important and advanced concepts that will help you write more powerful and efficient code.
Just like we covered intermediate concepts in Part 4, in this part too we will provide theory along with real-life examples and practical exercises, which will make it easier for you to understand complex topics. Whether you are a beginner or at the intermediate level, this tutorial will help you take your Swift skills to the next level.
By the end of Part 5, you will have a good command over the essential concepts of Swift, and you will be ready for the advanced topics ahead.
Come on, let’s get started and make your Swift journey more interesting!
In Part 5, we will build your foundation by diving into the basics of Swift:
Defer
defer is a special keyword that allows you to perform some actions at the end of a code block, whether the execution of the function succeeds or fails. It is used in situations where you need to perform clean-up tasks, such as closing files, releasing resources, or completing a task.This keyword in Swift follows the LIFO (Last In, First Out) structure, meaning the last deferred block gets executed first when the function exits.
Where does Defer work?
- While using defer whatever is written at the end of the code block is finally executed.
- Important: This code block is executed at the end of the function, even if the function has a return statement earlier.
Example
func processFile() {
print("File processing started.")
// Defer block
defer {
print("Closing the file.")
}
print("Processing the file data...")
// Some file processing logic goes here...
// Returning early, but defer block will still run at the end
return
}
processFile()
// OUTPUT
File processing started.
Processing the file data...
Closing the file.
How LIFO Works with defer
?
When you use multiple defer blocks in a function, they are executed in reverse order of how they appear in the code. So, the last defer block that is written in the function will be the first one to execute when the function exits.
func processTransaction() {
print("Starting transaction.")
defer {
print("Transaction rolled back.")
}
defer {
print("Logging transaction.")
}
defer {
print("Closing database connection.")
}
print("Processing transaction...")
// Some transaction processing code here...
}
processTransaction()
// Output
Starting transaction.
Processing transaction...
Closing database connection.
Logging transaction.
Transaction rolled back.
We have three defer blocks in the function, each handling a different action: closing a connection, logging, and rolling back the transaction.
Even though the defer blocks are written in the order of closing connection, logging, and rolling back, they execute in the reverse order when the function exits. So the “Closing database connection” message prints first, followed by “Logging transaction”, and then “Transaction rolled back.”
Lazy Properties and Initialization:
Lazy properties in Swift are a special kind of property that is not initially initialized until it is used. Meaning, a lazy property is not loaded into memory until you access it.
Lazy properties are used when you do not need to initialize a property until you use it. This is particularly useful when the cost of initialization is high, such as for heavy objects or complex computations.
class DataManager {
// Lazy property ka declaration
lazy var data = loadData()
// Heavy initialization function
func loadData() -> [String] {
print("Data is being loaded...")
return ["Item1", "Item2", "Item3"]
}
}
let dataManager = DataManager()
print("DataManager created.") // Data abhi tak load nahi hua
// Lazy property ko access karte hain
print(dataManager.data) // Data is being loaded... ["Item1", "Item2", "Item3"]
// OUTPUT
DataManager created.
Data is being loaded...
["Item1", "Item2", "Item3"]
- lazy var data = loadData() is a lazy property. When the object of dataManager is created, then the data property is not initialized.
- Till we do not access dataManager.data, loadData() function is not called.
- When we access dataManager.data for the first time, then loadData() function is called and data is loaded.
Subscripts
Subscripts are a simple way you can directly access elements of arrays, dictionaries, or custom collections without methods. They are a shortcut to retrieving or updating data via an index or key.
struct Numbers {
var values: [Int]
subscript(index: Int) -> Int {
get {
return values[index]
}
set(newValue) {
values[index] = newValue
}
}
}
var numbers = Numbers(values: [10, 20, 30])
print(numbers[1]) // Output: 20
numbers[2] = 100
print(numbers[2]) // Output: 100
Explanation: Here by using subscript we are directly accessing and modifying the array elements.
Simple Access: Subscript can be used to access the elements of the collection directly.
Mutability: If you use set block then you can also modify the value.
Custom Collections: You can also use Subscript in your custom collections.
Initalization
Sure! Here’s an explanation of Initialization in Swift in Hinglish, along with detailed English code examples:
Initialization in Swift: Kya Hai?
Initialization means giving an initial state to the object when it is created. In Swift, when you create an object of a class, struct, or enum, you have to give an initial value to the properties of that object. We call this process initialization.
For initialization in Swift, you have to use initializers (constructors).
struct Person {
var name: String
var age: Int
// Default initializer
init(name: String, age: Int) {
self.name = name
self.age = age
}
}
let person = Person(name: "John", age: 30)
print("Name: \(person.name), Age: \(person.age)") // Output: Name: John, Age: 30
- init is an initializer in which name and age are being initialized.
- When we write Person(name: “John”, age: 30), Swift calls the init method to create the object and assigns initial values to the properties.
- Here self.name and self.age are used to set the properties of the object.
Key Points About Initialization:
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]
- Default Initializer: If you don’t define a custom init method, Swift automatically generates a default initializer.
- Custom Initializer: You can define an init method to initialize your objects with custom values.
- Failable Initializer: If a condition fails in your initialization, you can return nil using init?.
- Optional Properties: You can make properties optional and set them to nil before initializing them.
Conclusion
In Part 2 of our Swift programming journey, we laid a solid foundation by covering key concepts like Generics, Higher Order Function , Memory Management, Collection Type. These core topics help you write safe, efficient, and organized Swift code — essential for everyday development.
In this part 3, we’ll unlock some game-changing tools that every Swift developer needs to know to build scalable, robust, and flexible applications:
Leave a Reply