iOS Interview Question (Part 3)

--

1. Does closures capture values?

Yes, closures in Swift can capture and store references to values from their surrounding context. This is known as capturing values or creating a closure’s capture list.

When a closure captures a value, it captures a reference to the value itself, rather than making a copy of it. This means that the closure holds a reference to the original value even if the original scope that defined the value goes out of scope.

Here’s an example to illustrate value capture in closures:

func makeIncrementer(incrementAmount: Int) -> () -> Int {
var total = 0

let incrementer: () -> Int = {
total += incrementAmount
return total
}

return incrementer
}
let incrementByTwo = makeIncrementer(incrementAmount: 2)
print(incrementByTwo()) // Output: 2
print(incrementByTwo()) // Output: 4

In this example, the makeIncrementer function returns a closure that captures the incrementAmount and total variables. The closure increments the total variable by the incrementAmount and returns the updated total value.

When makeIncrementer is called, it creates a new instance of total and returns the closure. Each time the closure is called (incrementByTwo()), it captures and modifies the same total variable, maintaining its state between calls.

The closure captures the values it references, in this case, incrementAmount and total, allowing it to access and modify them even after the makeIncrementer function has finished executing.

2. What is Trailing Closure?

Write a closure as the last argument of a function or method call.

Trailing closures are particularly useful when the closure’s body is long or when the closure enhances the readability and clarity of the code.

Here’s an example to illustrate the usage of a trailing closure:

func performOperation(on number: Int, operation: (Int) -> Int) -> Int {
return operation(number)
}

let result = performOperation(on: 5) { (number) in
return number * 2
}
print(result) // Output: 10

In this example, the performOperation(on:operation:) function takes an Int argument number and a closure operation that takes an Int and returns an Int. The closure is used to perform some operation on the number argument.

Instead of passing the closure as a separate argument inside the parentheses, you can use a trailing closure:

let result = performOperation(on: 5) { number in
return number * 2
}

By placing the closure after the function call and removing the argument label, the closure is treated as a trailing closure. This syntax enhances readability and separates the closure’s logic from the function call, making the code easier to read and understand.

Trailing closures are especially helpful when working with functions that take higher-order functions or when using functions like map, filter, or reduce that accept closures as their last arguments.

3. What is Encapsulation? Example? Advantages?

Binding property and methods into a single class is called encapsulation.Encapsulation helps to achieve data abstraction, data hiding, and information security.
Example:

class BankAccount {
private var balance: Double = 0.0

func deposit(amount: Double) {
balance += amount
}

func withdraw(amount: Double) {
if amount <= balance {
balance -= amount
} else {
print("Insufficient funds")
}
}

func getBalance() -> Double {
return balance
}
}


let account = BankAccount()
account.deposit(amount: 1000)
account.withdraw(amount: 500)
print(account.getBalance()) // Output: 500.0

In this example, the BankAccount class encapsulates the balance property and the methods deposit, withdraw, and getBalance. The balance property is marked as private, which means it can only be accessed within the class. External entities can interact with the object by using the public methods provided, such as deposit and withdraw, without directly accessing or modifying the internal state of the object.

4. Can we use var in optional binding or guard statement instead of let?

In Swift, you cannot use var in optional binding (if let or guard let) statements. The reason for this is that optional binding is intended to provide a way to safely unwrap an optional value and create a new constant (using let) with that unwrapped value if it exists.

The syntax for optional binding with if let is as follows:

if let unwrappedValue = optionalValue {
// Code block to execute when optionalValue is not nil
}

Similarly, the syntax for optional binding with guard let is as follows:

guard let unwrappedValue = optionalValue else {
// Code block to execute when optionalValue is nil
// Use return, break, continue, or throw to exit the scope if necessary
}
// Code block to execute when optionalValue is not nil

The idea behind using let instead of var is to ensure that the unwrapped value is immutable within the scope of the if-let or guard-let statement. This helps prevent accidental modifications to the unwrapped value, ensuring the safety of the optional binding operation.

5. What happens when you call a method over optional whose value is nil?

When you call a method on an optional value that is nil, nothing happens. In Swift, calling a method or accessing a property on a nil optional results in no operation or value returned.

Here’s an example to illustrate this behavior:

class MyClass {
func myMethod() {
print("Method called")
}
}

var myInstance: MyClass? = nil
myInstance?.myMethod() // No output, nothing happens

In the code above, myInstance is an optional variable of type MyClass that is assigned nil. When you call myMethod() on myInstance using optional chaining (myInstance?.myMethod()), the method is not executed because the optional value is nil. It simply returns nil as the result without performing any operation.

Optional chaining allows you to call methods, access properties, or subscript on an optional value without having to explicitly unwrap it. If the optional value is nil, the chain is short-circuited, and the overall expression evaluates to nil without executing any further code.

However, it’s important to note that if the method you’re calling has a return type other than Void (i.e., it returns a value), calling it on a nil optional will result in nil being returned as well. For example:

class MyClass {
func myMethod() -> String {
return "Method called"
}
}

var myInstance: MyClass? = nil
let result = myInstance?.myMethod() // result will be nil

In this case, result will be nil because the method call returns nil due to the optional value being nil.

Please like and follow if you really like my article, it motivates me to continue….

--

--

No responses yet