Part 3: iOS interview Questions

Welcome back to the third installment of our “Basic iOS InterView question” series. In the last part, we covered some foundational concepts that every aspiring iOS developer should know. As we continue our journey, this part will delve deeper into the core aspects of iOS development. Whether brushing up on your knowledge or preparing for an upcoming interview, these questions and explanations will help solidify your understanding of essential iOS principles. Let’s dive in and explore the next set of crucial topics for acing your basic iOS interview.

51. What is an enum in Swift? How to use it?

An enum in Swift is a type that allows you to define a group of related values in a type-safe way. Enums are handy when you have a fixed set of options known at compile-time. Each case in the enum represents one of those options.

Basic Example

Here’s a simple example of an enum in Swift:

enum CompassDirection {
    case north
    case south
    case east
    case west
}

In this example, CompassDirection is an enum with four possible cases: north, south, east, and west.

Using an Enum

You can create a variable or constant of the CompassDirection type and assign it a value:

var direction = CompassDirection.north

Once the variable is assigned an enum case, you can change its value like this:

direction = .south

52. What is the difference between an Array and a Set?

In Swift, Array and Set are both collections used to store multiple values, but they have some key differences in terms of behaviour, use cases, and performance.

ArraySet
Maintains order; elements accessed by index.No specific order; elements cannot be accessed by index.
Allows duplicates; same value can appear multiple times.Only unique elements; and duplicates are ignored.

Constant-time (O(1)) index access; slower searching (O(n)).
Faster lookups (O(1)); no indexing.
Ideal for maintaining order and accessing elements by position.Best for unique elements and fast lookups.
Mutable with var can add, remove, or change elements.Mutable with var; can insert, remove, or update elements.
Ordered, allows duplicates, index-based access.Unordered, no duplicates, faster lookups.

53. What is typecasting? What is the difference between as, as?, and as! ?

Typecasting in Swift is the process of converting an instance of one type to another. This is particularly useful when you work with types that are part of a class hierarchy or when you’re dealing with protocols. Swift provides three operators for typecasting: as, as?, and as!.

Let’s dive into typecasting operators.

as:

  • Used for upcasting or guaranteed type conversion.
  • No optional involved.

as?:

  • Used for conditional downcasting.
  • Returns an optional (T?), and safely fails to nil if the cast is not possible.

as!:

  • Used for forced downcasting.
  • Returns a non-optional (T), and crashes the program if the cast fails.

54. What is the difference between IBDesinable and IBInspectable?

@IBDesignable and @IBInspectable are two attributes in Swift that allow you to enhance the way you work with Interface Builder in Xcode. They enable you to see and customize your custom UI components directly within the Interface Builder, providing real-time feedback as you design your user interfaces.

@IBDesignable

  • Purpose: Allows Interface Builder to render your custom views live in the storyboard or XIB. When you apply @IBDesignable to a UIView subclass, Xcode will compile and render that view in Interface Builder, showing how it will look at runtime.

@IBInspectable

  • Purpose: Exposes properties of your custom views to Interface Builder so that you can modify them in the Attributes Inspector. When you apply @IBInspectable to a property, that property becomes editable within Interface Builder.

55. What is the difference between nil, Nil, null and NSNull, .none?

nil: Used in Swift and Objective-C to represent the absence of a value or a null pointer in object and optional types.

Nil: Used in Objective-C specifically for null pointers to class types.

null: Not used in Swift/Objective-C, but common in other languages to represent the absence of a value.

NSNull: An Objective-C class used to represent null in collections where nil is not allowed.

.none: A case of Swift’s Optional enum that represents the absence of a value, equivalent to nil.

56. What is the difference between Any and AnyObject?

In Swift, Any and AnyObject are used to represent values of any type, but they have distinct purposes and are used in different contexts. Here’s a breakdown of the differences between them:

Any

  • Purpose: Represents an instance of any type, including all types (e.g., classes, structs, enums, functions, and even optionals).
  • Type: Universal type that can hold any kind of value, including both value types and reference types.
  • Usage: Use Any when you need to work with values that could be of any type, not just class types.
var anything: Any = "Hello, World!" anything = 42 anything = [1, 2, 3] anything = (3.14, "Pi")

AnyObject

  • Purpose: Represents an instance of any class type. It can only refer to instances of classes.
  • Type: Used for reference types only, meaning it can hold any object instance.
  • Usage: Use AnyObject when you need to work with values that are guaranteed to be class instances.
class MyClass {} var object: AnyObject = MyClass()

57. What is an Extension? When to use?

In Swift, an extension is a powerful feature that allows you to add new functionality to an existing class, structure, enumeration, or protocol type. This can include adding methods, computed properties, initializers, and conforming to protocols. Extensions help you organize your code better and enhance types without subclassing or modifying the source code.

What is an Extension?

An extension in Swift is a way to extend the functionality of an existing type. It lets you add new features to a type even if you don’t have access to its original implementation, or if you want to separate the functionality into different files for better organization.

Key Features of Extensions

  1. Add Methods: You can add new instances and type methods.
  2. Add Computed Properties: You can add computed properties but not stored properties.
  3. Add Initializers: You can add new initializers to a type.
  4. Add Subscripts: You can add new subscripts to a type.
  5. Make Types Conform to Protocols: You can extend types to conform to protocols, adding protocol-specific methods and properties.

58. What are the value type and reference type?

In Swift, types are categorized into two main categories: value types and reference types. Understanding the differences between these two categories is crucial for managing memory efficiently and ensuring the correct behaviour of your code.

Value Types

Definition: Value types are types where each instance keeps a unique copy of its data. When you assign a value type to a new variable or pass it to a function, a copy of the value is created.

Usage:

  • When to Use: Use value types when you want to ensure that each instance of a type maintains its own copy of data, and when you want to avoid unintended side effects caused by shared references.

Reference Types

Definition: Reference types are types where each instance shares a single copy of its data. When you assign a reference type to a new variable or pass it to a function, you are passing a reference to the same instance, not a copy.

Usage:

  • When to Use: Use reference types when you need instances to share data and maintain a single, mutable copy of the data.

59. What is Predicate? How to use it?

A predicate in Swift is an expression that evaluates to a Boolean value (true or false) and is used to filter collections or perform complex queries. Predicates are commonly used with Core Data to fetch objects from a database, but they can also be used to filter arrays and other collections.

Understanding Predicates

A predicate is essentially a condition that can be applied to a set of objects. It specifies criteria that determine whether an object should be included in a result set or not. In Swift, you typically use the NSPredicate class to define these conditions.

Example:

let fruits = ["Apple", "Banana", "Cherry", "Mango", "Orange"]

// Create a predicate to filter fruits that contain the letter 'a' let predicate = NSPredicate(format: "SELF CONTAINS[c] %@", "a")

// Use the predicate to filter the array

let filteredFruits = fruits.filter { predicate.evaluate(with: $0) } print(filteredFruits)

// Output: ["Apple", "Banana", "Mango", "Orange"]

60. What is the difference between map and compactMap?

In Swift, both map and compactMap are used to transform elements in a collection, but they differ in how they handle nil values during the transformation.

Key Differences Between map and compactMap

AspectmapcompactMap
TransformationTransforms each element in the collection.Transforms each element and removes nil values.
Handling of nilIncludes nil in the result if the transformation returns it.Discards nil values, returning only non-optional elements.
OutputReturns an array with optional values (if transformation can fail).Returns an array of non-optional values.

61. What is the difference between sort () and sorted ()?

In Swift, both sort() and sorted() are used to arrange the elements of a collection in a specific order, but they behave differently in terms of mutability and return types.

Key Differences

Aspectsort()sorted()
MutabilityMutates the original collection (in-place).Does not modify the original collection.
Return ValueNo return value (Void).Returns a new sorted array.
UsageUsed when you want to sort the original collection directly.Used when you want to keep the original array and create a new sorted one.
PerformanceMore efficient if you don’t need to preserve the original collection.May involve additional memory since a new array is created.

62. Closures are value types or reference types?

Closures in Swift are reference types. Here’s an explanation of why:

Closures and Reference Semantics

  • Memory Sharing: Closures in Swift capture references to variables and constants from their surrounding context, and this behaviour is typical of reference types. When a closure is assigned to multiple variables or passed around, they all refer to the same instance of the closure, not a copy.
  • Heap Allocation: Closures can capture values from their surrounding scope. If a closure captures values, these captured variables are stored on the heap, and multiple references to the closure will share the same captured data.

Example of Reference Behavior

var x = 10
let closure = { x += 5 }
let anotherClosure = closure  // anotherClosure refers to the same closure

anotherClosure()
print(x)  // Output: 15 (both closures refer to the same reference)

In this example, modifying x through anotherClosure() affects the same captured reference in closure.

Comparison with Value Types

  • If closures were value types, assigning them to a new variable or passing them around would result in copies, and changes in one closure wouldn’t affect others. However, in Swift, closures retain shared references to the captured variables.

63. What is the difference between an app and a framework?

The difference between an app and a framework is primarily in their purpose, structure, and usage within software development. Here’s a breakdown of how they differ:

1. App (Application)

An app (application) is a complete software product that is designed to perform a specific set of tasks for the end user. It is a standalone executable that interacts directly with users and provides functionalities that solve specific problems or fulfil user needs.

2. Framework

A framework is a reusable set of code, tools, libraries, and resources that developers can use to build apps. It provides predefined functionality that developers can use to avoid writing boilerplate code and helps with modularity and code reuse.

Key Differences

AspectAppFramework
PurposeProvides a complete, functional product for end users.Provides reusable components and functionality for developers.
User InteractionDirectly interacts with end users via UI.Does not interact with users; meant for developer use.
StandaloneRuns independently as a complete product.Requires integration into an app or another software product.
ExecutionPackaged as an executable file.Not executable; it’s a collection of code and resources.
CustomizationCustomizable and unique for each use case.Generic, reusable code meant to be integrated into various apps.
ExamplesWhatsApp, Instagram, Microsoft WordUIKit, Foundation, CoreData, Alamofire (third-party framework)

64. What is the maximum size of a push notification payload?

Apple increased the size limit for notification payloads to 4096 bytes(4KB) for iOS 8 and later.

65. How to use conditions with a for loop?

In Swift, you can use conditions within a for loop in several ways to control the flow or iteration based on certain criteria. You can include conditions directly in the loop structure, or use control statements like if, continue, or break inside the loop body to handle conditions dynamically.

Techniques:

  • if inside for: To check conditions within each iteration.
  • continue: To skip the current iteration when a condition is met.
  • break: To exit the loop entirely when a condition is met.
  • where clause: To filter iterations in the for loop directly.
  • guard: To handle early exits based on a condition.

66. Exception handling in Swift

Exception handling in Swift is primarily done using the do-catch mechanism, which is designed to handle errors in a clear and controlled manner. Unlike some other languages, Swift doesn’t have traditional exceptions like try-catch runtime errors; instead, it uses a more deliberate approach for handling recoverable errors, known as error handling.

Error Handling in Swift: Key Concepts

  1. Error Protocol: In Swift, any type that conforms to the Error protocol can be thrown and caught.
  2. Throwing Functions: Functions that can throw errors must be marked with the throws keyword.
  3. Do-Catch: A do block is used to try code that can throw an error, and the catch block handles the error if one is thrown.
  4. Try: The try keyword is used to call a function that can throw an error.
  5. Propagating Errors: Errors can be propagated up to the caller using the throws keyword.
  6. Optional Handling: The try? or try! syntax allows you to handle errors by either returning an optional or force-unwrapping the result.

67. Can protocols in Swift have variables?

Yes, protocols in Swift can have variables, but there are some important distinctions regarding how variables (also referred to as properties) are defined in protocols and implemented in conforming types.

Protocol Properties in Swift

In Swift, protocols can require conforming types to have properties, but the protocol itself does not store these properties. Instead, it specifies the requirements for those properties, and it’s up to the conforming type (class, struct, or enum) to implement them.

Defining Variable Requirements in Protocols

When defining properties in a protocol, you specify whether the property is:

  • gettable: The property must be readable.
  • settable: The property must be both readable and writable.

You can define protocol properties with the following syntax:

  • var propertyName: Type { get } – Read-only requirement.
  • var propertyName: Type { get set } – Read-write requirement.

Example of Protocol with Variables:

protocol Vehicle {
    var numberOfWheels: Int { get }
    var color: String { get set }
}
  • numberOfWheels is read-only (get).
  • color is read-write (get set).

68. What is Code signing?

Code signing is a security process used to certify the authenticity and integrity of software code, ensuring that it has not been altered or tampered with after being signed by the author or a trusted authority. It is especially important in environments like iOS or macOS development, where code must be trusted by the operating system before it is executed.

In Swift (or more broadly, Apple’s ecosystem), code signing is essential when building apps for iOS, macOS, watchOS, and tvOS. This process uses a digital signature to prove that the code comes from a known developer and has not been modified since it was signed.

Code Signing in Xcode:

Xcode automates the code signing process, and the developer doesn’t need to manage the signing manually most of the time. When you build and run your app on a device, Xcode:

  • Signs the app with a development certificate.
  • Uses a provisioning profile that matches the code signing identity and device.

69. What is an availability condition and how to use it?

An availability condition in Swift is used to check if a specific API, framework, or feature is available on the version of the operating system (iOS, macOS, etc.) that the code is running on. This helps you write code that is compatible with multiple OS versions, ensuring that certain features are only used when they are available in the target environment.

This is particularly important when supporting older OS versions, as newer APIs may not be available on all devices.

Syntax for Availability Condition

The #available keyword is used to specify availability conditions in Swift. The syntax is as follows:

if #available(platform version, *) {
    // Code to execute if the platform version is available
} else {
    // Fallback code for older versions
}

70. How many bits are used to store an Int?

The number of bits used to store an Int in Swift depends on the platform and the architecture of the device:

  • On a 32-bit platform, an Int is stored using 32 bits.
  • On a 64-bit platform, an Int is stored using 64 bits.

Swift’s Int type is an integer type with platform-specific size. The size of Int is automatically set based on the underlying architecture, meaning that on 32-bit systems, Int is the same as Int32, and on 64-bit systems, Int is the same as Int64.

71. What is the accessibility identifier?

An accessibility identifier in iOS development is a property of a user interface element that serves as a unique string to identify that element, primarily for UI testing purposes. It is used by tools like XCUITest to locate and interact with UI elements during automated tests.

Purpose of Accessibility Identifier:

  • UI Testing: Accessibility identifiers allow automated tests to reliably identify and interact with UI elements (such as buttons, labels, or text fields). This ensures that tests don’t rely on UI layout or other attributes that may change over time.
  • Debugging: When performing UI automation tests, the accessibility identifier can make it easier to reference specific elements in the app.
  • Accessibility: While it shares some concepts with accessibility features, the accessibility identifier is not specifically used for screen readers. It is solely intended for testing purposes.

72. What is the difference between static variable and instance variable?

In Swift, static variables and instance variables differ in how they are associated with a type or an instance of that type:

1. Instance Variable:

  • Belongs to an instance of a class, struct, or enum.
  • Each instance of the type has its own copy of the instance variable.
  • Accessed through the instance of the type.

Key Characteristics:

  • Every instance of the type has a unique copy of the instance variable.
  • Changing the value of an instance variable in one instance does not affect other instances.

2. Static Variable:

  • Belongs to the type itself, not to any instance of the type.
  • All instances of the type share the same static variable.
  • Accessed using the type name, not the instance.
  • Declared using the static keyword in structs and enums, or class keyword in classes (though static can be used in classes too, but class allows overriding).

Key Characteristics:

  • There is only one copy of a static variable, shared among all instances of the type.
  • Changing the value of a static variable affects all instances.

73. What is the difference between self and Self?

In Swift, self and Self are two distinct concepts with different meanings:

1. self (lowercase)

  • Refers to the current instance of a class, struct, or enum.
  • You use self when you want to refer to the instance’s properties or methods from within the instance itself.

Usage:

  • Accessing instance variables or methods from within the same object.
  • Passing the current instance to a function or closure.

Example:

struct Person {
    var name: String
    
    func introduce() {
        print("Hello, my name is \(self.name)")  // 'self' refers to the current instance of Person
    }
}
let john = Person(name: "John")
john.introduce()  // Outputs: Hello, my name is John

In this case, self.name refers to the name property of the current Person instance (john).

2. Self (uppercase)

  • Refers to the type itself, not the instance. It is primarily used in generic programming and within protocols to refer to the type that conforms to the protocol or in static methods of types (e.g., class, struct, enum).
  • In the context of a protocol, Self refers to the conforming type.
  • In static or class methods, Self refer to the type that the method is called on (class, struct, or enum).

Usage:

  • To define return types in protocols that refer to the type itself.
  • In static/class methods refers to the type rather than an instance.

Example 1 (Static method):

struct Circle {
    var radius: Double
    
    static func createUnitCircle() -> Self {
        return Self(radius: 1.0)  // 'Self' refers to the 'Circle' type
    }
}
let unitCircle = Circle.createUnitCircle()  // Returns a Circle instance with radius 1.0

74. Explain conditional conformances in Swift.

Conditional conformances in Swift allow a generic type to conform to a protocol only when certain conditions are met. This means that a type can conform to a protocol if and only if its generic parameters meet specific requirements. Conditional conformances enable more flexible and expressive code, especially when dealing with complex types like collections or custom generics.

Why Are Conditional Conformances Useful?

Imagine a situation where you want an array of elements to conform to a protocol like Equatable, but only if the elements inside the array are Equatable. Conditional conformances allow you to define such behaviour, making your code more modular and reusable.

Syntax

Conditional conformances are defined using where clauses that specify the conditions under which a type conforms to a protocol.

extension Array: Equatable where Element: Equatable {
    // Array only conforms to Equatable if its elements are Equatable
}

In the above example, Array conforms to Equatable only if its generic type Element conforms to Equatable.

75. Can we add a stored property to type through an extension?

No, in Swift, you cannot add stored properties to a type through an extension. Extensions can only add computed properties, methods, initializers, and subscripts, and conform to protocols, but not stored properties.

The third instalment of basic iOS interview questions focuses on more advanced foundational topics in Swift, Enum, Predicate, Typecasting, Extension, Closures, handling errors with do, try, and catch, and Protocols, It also covers Swift’s type system (e.g., Any, AnyObject, nil), the differences between Array, Set, and Dictionary, and the power of protocols and extensions, along with the concept of closures and how they capture values.

If you missed – Part 2 ⏩

Thanks for reading! I hope this will be useful for understanding or refreshing some of the iOS concepts. Please share your feedback, and queries regarding any of the topics in the comments below. Till then happy Coding!!! 💚💚💚💚💚💚💚💚💚💚

Leave a Reply

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