To run a reverse for loop in Swift, the cleanest and most common approach is to use the .reversed() method on a range or a collection.
1. Reverse Loop Over a Number Range
To count downwards between two numbers, wrap your range in parentheses and append .reversed():
// Counts down from 5 to 1 inclusive
for index in (1...5).reversed() {
print(index)
}
// Output: 5, 4, 3, 2, 1
// Counts down from 4 to 0 (excludes the upper bound 5)
for index in (0..<5).reversed() {
print(index)
}
// Output: 4, 3, 2, 1, 0
2. Reverse Loop Over an Array
let items = ["Apple", "Banana", "Cherry"]
for item in items.reversed() {
print(item)
}
// Output: Cherry, Banana, Apple
3. Reverse Loop with Index and Value
If you need both the index and the element while going backward, combine .reversed() with .enumerated().
let names = ["Alex", "Brian", "Chris"]
for (index, name) in names.reversed().enumerated() {
print("Index \(index) contains \(name)")
}
// Output:
// Index 2 contains Chris
// Index 1 contains Brian
// Index 0 contains Alex
4. Reverse Loop with Custom Step Sizes (stride)
// Inclusive stride
for index in stride(from: 10, through: 0, by: -2) {
print(index)
}
// Output: 10, 8, 6, 4, 2, 0
What is compile time and runtime error
The core difference is that compile-time errors prevent your program from building, while runtime errors occur while the program is executing.
Compile-Time Error:
During code compilation (before running).
Prevent an executable from being created.
Runtime Error:
During program execution.
Program crashes or behaves unpredictably.
A generic function in Swift allows you to write flexible, reusable code that can work with any data type while maintaining complete type safety. Instead of duplicating logic for Int, String, or Double, you use a placeholder type (conventionally named T) inside angle brackets ().
Basic Syntax
// Defining a generic function with a placeholder type T
func printValue<T>(_ value: T) {
print("The value is: \(value)")
}
// Swift automatically infers the concrete type at runtime
printValue(42) // T becomes Int
printValue("Hello") // T becomes String
printValue(3.14) // T becomes Double
In Swift, the Comparable protocol is used to define a natural relational order for instances of a type. Conforming to Comparable allows you to use relational operators like <, >, <=, and >=, and unlocks standard library capabilities like sorting an array with a parameterless .sorted() method.
func findLargest(_ a: T, _ b: T) -> T {
return a > b ? a : b
}
let highestScore = findLargest(85, 92) // Works with Int
let alphabetLast = findLargest("apple", "banana")
print(highestScore) // 85
print(alphabetLast) // banana
In Swift, subscripts are shortcuts used to access or modify member elements of a collection, list, or sequence without explicitly calling a method. They allow you to use bracket notation like instance[index] directly on your custom classes, structures, and enumerations.
Subscript declarations resemble a mix of instance methods and computed properties. They are defined using the subscript keyword, taking input parameters and specifying a return type.
struct SimpleList {
var items: [String]
// Read-and-Write Subscript
subscript(index: Int) -> String {
get {
return items[index]
}
set(newValue) {
items[index] = newValue
}
}
}
struct Multiplier {
let factor: Int
// Read-only shortcut
subscript(number: Int) -> Int {
return number * factor
}
}
let threeTimes = Multiplier(factor: 3)
print(threeTimes[6]) // Prints 18
Safe Array Access
extension Array {
subscript(safe index: Int) -> Element? {
return indices.contains(index) ? self[index] : nil
}
}
let names = ["Alice", "Bob"]
print(names[safe: 5]) // Prints nil (No runtime crash!)
why Functional Programming swift explain
Functional Programming (FP) in Swift is a paradigm that treats computation as the evaluation of mathematical functions, heavily emphasizing immutability and preventing state changes. Swift is designed from the ground up as a multi-paradigm language, meaning it natively blends Object-Oriented Programming (OOP) with powerful, built-in features for Functional Programming.
Implementing functional patterns in Swift eliminates hidden side effects, ensures inherent thread safety, and dramatically simplifies unit testing.
Core Concepts of Functional Swift
- Immutability & Value Types
let over var: Using let guarantees that data cannot be modified after creation, removing unexpected state changes.
Value Types (Structs and Enums): Unlike classes (which are reference types), structs are passed by value. When passed to a function, Swift copies the data, ensuring other parts of the app cannot accidentally overwrite it.
- First-Class and Higher-Order Functions
Functions that accept or return other functions are known as Higher-Order Functions. The Swift Standard Library natively includes several higher-order tools to process data without using manual loops:
map: Transforms every item in a collection.
filter: Extracts items matching specific conditions.
reduce: Combines all elements into a single value.
let numbers = [1, 2, 3, 4, 5]
// Declarative functional chain vs. Imperial "for" loop
let doubledEvens = numbers
.filter { $0 % 2 == 0 } // Filters out odd numbers
.map { $0 * 2 }
can we use lazy let in swift instead of lazy var
No, you cannot use lazy let in Swift. Swift strictly requires you to use lazy var
The Swift compiler will throw a compile-time error if you attempt to use lazy let.
Why Swift Doesn't Allow lazy let
If your goal is to make sure a lazy property cannot be modified by other parts of your code after it initializes, you can use the private(set) modifier.
class DataManager {
// Read-only to the outside world, but mutates internally on first access
private(set) lazy var expensiveData: [String] = {
print("Loading heavy data...")
return ["Data 1", "Data 2", "Data 3"]
}()
}
let manager = DataManager()
// 1. Works perfectly and triggers initialization
print(manager.expensiveData)
// 2. Compiler Error: Cannot assign to property: 'expensiveData' setter is inaccessible
manager.expensiveData = ["New Data"]
in unowned can we use let or var both swift
The choice between let and var purely depends on whether you want the reference itself to be mutable (re-assignable) or immutable (constant). This is a major structural advantage over weak, which must always be declared as a var because Automated Reference Counting (ARC) dynamically zeroes it out to nil when the referenced instance deallocates.
Using unowned let
Use unowned let when the reference is assigned exactly once during initialization and never changes.
It creates an immutable binding between an object and its non-strong dependency.
class Customer {
let name: String
init(name: String) { self.name = name }
}
class CreditCard {
let number: UInt64
// The owner never changes, but we don't want a strong reference cycle
unowned let owner: Customer
init(number: UInt64, owner: Customer) {
self.number = number
self.owner = owner
}
}
throw vs throws in swift ios
In Swift, throws is used in a function's declaration to signal that it can potentially fail, while throw is the action keyword used inside the function to execute and raise a specific error.
throws
Declares that a method, closure, or property can encounter and propagate a failure.
**Example
func check(id: Int) throws -> Bool**
throw
Triggers the actual failure, immediately halting execution and passing the error out.
**Example
throw NetworkError.timeout**
Implementation Example
To use error handling in iOS development, you must first define an enum that conforms to Swift's standard Error protocol.
// 1. Define your error types
enum ValidationError: Error {
case emptyUsername
case textTooShort
}
// 2. Use 'throws' in the signature to designate a throwing function
func validate(username: String) throws -> Bool {
guard !username.isEmpty else {
// 3. Use 'throw' to explicitly raise the error state
throw ValidationError.emptyUsername
}
guard username.count >= 3 else {
throw ValidationError.textTooShort
}
return true
}
H*ow to Call a Throwing Function*
When a function is marked with throws, the Swift compiler prevents you from executing it normally. You must handle it using a do-catch block combined with the try keyword:
do {
let isValid = try validate(username: "Al")
print("Success: \(isValid)")
} catch ValidationError.emptyUsername {
print("Please enter a username.")
} catch ValidationError.textTooShort {
print("Username must be at least 3 characters.")
} catch {
print("An unknown error occurred: \(error).")
}
In Swift, a standard parameter is a read-only copy. An inout parameter allows a function to modify the original variable directly.
Without inout (Copy)
var score = 10
func addBonus(points: Int) {
// points is a copy.
// Changing it here does not affect 'score'.
points += 5
}
addBonus(points: score)
print(score) // Output: 10
With inout (Reference)
To use inout:
- You must declare the original variable using var (not let).
- You must add the inout keyword before the parameter type.
- You must put an ampersand (&) before the variable name when you call the function.
var score = 10
// 1. Mark the parameter as inout
func addBonus(points: inout Int) {
// 2. Modifying it updates the original variable
points += 5
}
// 3. Put & before the variable when calling
addBonus(points: &score)
print(score) // Output: 15
in swift can we Inheritance with Structures
No, structures in Swift do not support inheritance. In Swift, inheritance is a feature exclusive to classes. A struct cannot inherit from another struct or class, nor can it serve as a base type for another structure to inherit from.
Instead of classical inheritance, Swift relies heavily on Protocol-Oriented Programming and Composition to share behavior among structures
AssociatedType
protocol Container {
associatedtype Item
mutating func add(_ item: Item)
func getItem() -> Item
}
struct IntContainer: Container {
var value = 0
mutating func add(_ item: Int) {
value = item
}
func getItem() -> Int {
value
}
}
var container = IntContainer()
container.add(100)
print(container.getItem())
Top comments (0)