Swift Interview 2023: Ace the Code

iOS — Swift Interview Questions 2023

Cracking the Code: iOS Swift Interview Questions for 2023 — A Comprehensive Guide to Ace Your Job Interview

Kanagasabapathy Rajkumar

--

Interview Questions 2023

Architecture

TCA

"If you're genuinely interested in learning about TCA, I recommend taking a look at my article."

A curated set of questions and answers

Difference between Class and Structure in Swift

Structure vs Class in Swift

When deciding whether to use a structure or a class, there are various factors to consider.

Where can we use the Structure and Class
Recommendation of Structure and Class

SwiftUI Topics

Delegation Pattern

The most important question that has been frequently asked during the interview sessions.

Delegate Pattern is a Design Pattern that enables one object to send messages to another object when a particular event occurs. This can be accomplished in Swift using a Protocol.

Delegation Pattern in Swift

Example of Delegation Pattern Using Protocol

// SomeProtocol.swift
protocol SomeProtocol{ //
func modifyTextToLabel(someText: String)
}

Protocol: Created SomeProtocol.swift and added a method to modify the text to the label of ViewController.

// FirstViewController.swift
class FirstViewController: UIViewController{
private lazy var someLabel: UILabel = {
let label = UILabel()
label.frame = CGRect(x: 100, y: 150, width: 100, height: 50)
label.text = "Default"
return label
}()
private lazy var someButton: UIButton = {
let button = UIButton(frame: CGRect(x: 100, y: 200, width: 100, height: 50))
button.setTitle("Press ME!", for: .normal)
button.backgroundColor = .red
button.addTarget(self, action: #selector(handleButtonTapped), for: .touchUpInside)
return button
}()
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .white
view.addSubview(someLabel)
view.addSubview(someButton)
}
}

ViewController: I have created the FirstViewController and added a label and button using lazy variables. This means that the initialization or computation will be delayed until it is needed.

// SecondViewController.swift
class SecondViewController: UIViewController, UITextFieldDelegate {
lazy var someTextField: UITextField = {
let textField = UITextField(frame: CGRect(x: 100, y: 100, width: 100, height: 60))
textField.placeholder = "Enter Text"
textField.keyboardType = .default
return textField
}()
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .white
view.addSubview(someTextField)
someTextField.delegate = self
}
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
return true
}
}

ViewController — Created another ViewController — SecondViewController and added a text field to get the user input. someTextField will conform to the UITextFieldDelegate protocol.

class FirstViewController: UIViewController, SomeProtocol {
func modifyTextToLabel(someText: String) {
self.someLabel.text = someText
}
}

FirstViewController conforms to the SomeProtocol and inherited the requirements (or methods).

class SecondViewController: UIViewController, UITextFieldDelegate {
weak var delegate: SomeProtocol? // weak variable to avoid retain cycles

func textFieldShouldReturn(_ textField: UITextField) -> Bool {
if textField.hasText {
delegate?.modifyTextToLabel(someText: textField.text ?? "")
navigationController?.popToRootViewController(animated: true)
return true
}
return false
}
}

“delegate” variable holds SomeProtocol and acts as Delegate between SecondViewController and FirstViewController. Assigned to weak reference to avoid retain cycles.

Here, “modifyTextToLabel” is a delegate method that helps in passing the data from SecondViewController to FirstViewController. Hence, the text of “someLabel” of the FirstViewController will be modified.

Did you know why Protocol using AnyObject?

Due to memory management, we have stored the delegate object in a weak property. However, we are encountering an issue where Xcode is throwing an error and preventing the code from running.

'weak' must not be applied to non-class-bound 'MyDelegate'; 
consider adding a protocol conformance that has a class bound

To eliminate this, we need to have a class-only protocol.

protocol SomeProtocol: AnyObject {
func modifyTextToLabel(someText: String)
}

Weak references are only applicable to reference types, which means value types such as structures or enumerations cannot conform to this protocol — SomeProtocol.

If an object conforming to the protocol needs to be stored in a weak property then the protocol must be class-only protocol.

UIKit Topics

What runtime checks do you follow in your Swift project?

During the iOS Development, we should ensure all the sanity checks have been performed before releasing the app to App Store.

1. Precondition
2. Assertion
3. Fatal Error
4. Guard

Precondition
Check a condition before proceeding with the code. If a condition evaluates fail, the program execution will be stopped.

Works well with both Production and Development

func preCondition(willRun: Bool) {
precondition(willRun)
print("Called \(#function) successfully")
}
preCondition(willRun: true) // Called preCondition(willRun:) successfully
preCondition(willRun: false) // Precondition failed: Must set willRun to true

func preConditionFailure(){
preconditionFailure("It will not run")
}
preConditionFailure() // Fatal Error: It will not run

Assertion

Good in Testing Driven Development (TDD). We can eliminate the issue during development and can be fixed early.

Works well with Development.

func assertion(willRun: Bool) {
assert(willRun)
print("Called \(#function) successfully")
}
assertion(willRun: true) // Called assertion(willRun:) successfully
assertion(willRun: false) // Assertion failed

func assertionFail() {
assertionFailure("Expected Failure")
print("Called \(#function) successfully")
}
assertionFail() // Fatal Error: Expected Failure

Fatal Error

Force a crash during some memory issues and always produces an error.

Apple won’t approve the app if this is used in our Production code.

Works well with Development

func testfatalError() {
fatalError("FatalError")
}
testfatalError() // Fatal Error: FatalError

We can make use of fatalError() in the TableView

tableView(_:cellForRowAtIndexPath:)

https://cocoacasts.com/what-is-fatalerror-in-swift-and-when-to-use-it/

Guard

Guard Statement defines different paths (true or false).

Satisfies the following scenarios —

  1. Early Exit if preconditions are failed
  2. Happy path — Early Return
  3. Visibility
  4. Can be used in the loops such as for and while.

Works well with both Production and Development

func testGuard(willCall: Bool) {
guard willCall else {
print("No Call"
return
}
print("Called \(#function) successfully")
}
testGuard(willCall: true) // Called testGuard(willCall:) successfully
testGuard(willCall: false) // No Call

Why conform the NSObject to the Swift class? Do we require to do so?

Before answering this question, we need to understand the need for NSObject.

What is NSObject?

The NSObject is universally recognized as the base class for all Cocoa Touch classes, including all UIKit classes derived from it.

NSObject is an abstract class.

But we don’t have to inherit UIKit from NSObject in Swift, but we did it with Objective-C.

Benefits: Subclassing NSObject in Swift gets Objective-C runtime flexibility. Key mechanisms such as NSCoding, KVO, and Hashable.

Disadvantage: Performance is the drawback. We will get Objective-C Performance. Swift performs faster than Objective-C.

I would like to conclude that for pure Swift programming, we should avoid subclassing the NSObject.

UIKit Topics

What is POP?

At WWDC 2015, Apple announced that Swift is the world’s first Protocol-Oriented Programming (POP) language.

Definition of Protocol

The protocol is the blueprint of the methods, properties, subscripts, and so on that suit a particular task or functionality. Can be adopted by classes, structures, or enumerations to provide the actual implementation of the requirements.

If the requirements are satisfied, then it is called conform to protocol. The entire Swift Library is based on Protocols.

protocol Epics {
func isAMovie()
}

protocol Myths {
func isAMyth()
}

Extensions

Extension can extend the properties or methods of existing types without modifying actual implementation. Optional methods can be achieved through extensions.

Extension — Default Implementation: Default implementation to any property or method. Override methods defined in the parent
class.

extension Epics {
func isABook() {
print("Yes, isABook")
}
}

Protocol conforming to another protocol: A Protocol can
conform all the requirements to another protocol. We can achieve multiple
inheritance using Protocol.

Protocol Inheritance and Protocol Composition are both excellent examples of protocols.

Protocol Inheritance vs Protocol Composition

Before going to this topic, let’s understand the basic concepts.

What is Inheritance

Inheritance is OOP Paradigm and it means “subclassing the superclass”.
A subclass may override the properties or methods by altering the default behaviour.

Do value types support inheritance? No. Structures or enums don’t support
inheritance.

What is Composition

Composition is a combination of multiple parts to create a single outcome.

Do Structs works with Composition? Structure works well with the composition. Provides Better performance and memory safety.

Protocol Inheritance

In Swift, the protocol can inherit from other protocols, requiring to conform types to provide an implementation for all properties and methods in the entire hierarchy. The protocol can conform or inherit from other protocols and be separated by commas.

protocol FirstProtocol { 
var firstName: String {get}
}
protocol SecondProtocol {
var lastName: String {get}
}
struct Person: FirstProtocol, SecondProtocol {
var firstName: String = "First Name"
var lastName: String = "Last Name"
}

let person = Person()
print(person.firstName)
print(person.lastName)

Protocol Composition

Enables combining multiple protocols into a single requirement without defining new protocol type or new protocol hierarchy. Achieves Multiple Inheritance. List as many protocols and separated them with the
ampersand (&).

protocol FirstProtocol { 
var firstName: String {get}
}
protocol SecondProtocol {
var lastName: String {get}
}
struct Person: FirstProtocol & SecondProtocol {
var firstName: String = "First Name"
var lastName: String = "Last Name"
}

let person = Person()
print(person.firstName)
print(person.lastName)

Swifty Approach

We can make use of the Swifty approach by using “typealias” to clean the concatenation of protocols when it is messy and also reusable.

typealias SingleProtocol = FirstProtocol & SecondProtocol
protocol FirstProtocol {
var firstName: String { get }
}
protocol SecondProtocol {
var secondName: String { get }
}
struct NewStruct: SingleProtocol {
var firstName: String = "FirstName"
var secondName: String = "SecondName"
}

let newStruct = NewStruct()
print(newStruct.firstName)
print(newStruct.secondName)

What is typealias?

Typealias is a function that gives a new name or alias to an existing type. It can be a concrete type, complex structure, custom structure, or closure type. This will help make our code more readable and easy to maintain.

Choosing Between Protocol Inheritance and Protocol Composition

Use Protocol Composition — when the type conforms to multiple protocols simultaneously without introducing a new hierarchy.

Protocol Inheritance — To create a new protocol that builds upon the existing protocol’s requirements, extending its functionality.

Concrete Type vs Abstract Type

Within the Swift programming language, there exist various types of categories, including Concrete Types and Abstract Types, which are the two fundamental concepts.

What is Concrete Type?

Concrete type refers to the specific type that can be directly instantiated to create objects.

  1. We can define all properties and methods
  2. Classes and Structures are examples of concrete types

Simple Concrete Type

struct Person {
var name: String
var age: Int
}
let person = Person(name: "John", age: 20)
print("Person name \(person.name) Age \(person.age)")

Concrete type using Class

class Employee {
var name: String
var age: Int
init(name: String, age: Int) {
self.name = name
self.age = age
}
func empActiveStatus() {
print("Active")
}
}

let employee = Employee(name: "Jones", age: 35)
print("Employe name \(employee.name) Age \(employee.age)")
print("Active Status \(employee.empActiveStatus())")

What is Abstract Type?

An abstract type is a type that defines a set of requirements but does not provide actual implementation.

  1. Requirements refer to properties and methods
  2. Abstract type cannot be directly instantiated.
protocol Shape {
func area() -> Double
}
struct Circle: Shape {
var radius: Double
func area() -> Double {
return Double.pi * radius * radius
}
}
struct Square: Shape {
var side: Double
func area() -> Double {
return side * side
}
}

let circle = Circle(radius: 5.0)
print("Area of circle: ", circle.area())
let square = Square(side: 5.0)
print("Area of square: ", square.area())

How to achieve Abstract type?

The primary way to achieve or define abstract type is by using Protocol.

Did you know? A Protocol is an abstract type because it declares a requirement but there is no actual implementation.

To achieve this, we need to have a concrete type that conforms to the protocol and provides concrete implementation.

Summary

  1. Concrete type can be directly instantiated and used.
  2. The abstract type defines but does not provide concrete implementation like protocol.
  3. Defines common interface with multiple concrete types by enabling the Polymorphism

Exception Handling

Swift's exception handling or error handling process involves managing errors and exceptions. This process allows for the throwing, catching, and manipulation of errors during runtime.

Ways to Handle the Errors or Exceptions

  1. do
  2. try
  3. catch
  4. throw
  5. throws

Before handling the exceptions, we need to create an enum of Errors.

Enum of Errors: Create an enum that conforms to the Error Protocol so that we can throw the error value inside the
function.

enum CustomError: Error {
case someError
}

do-try-catch — do-catch will allow us to catch and handle the errors thrown from a block of code within the ‘do’ block

enum CustomError: Error {
case someError(message: String)
}
func someFunction() throws {
let randomNum = Int.random(in: 0...1)
if randomNum == 0 {
throw CustomError.someError(message: "Error A Occurred")
} else {
print("Function Executed successfully")
}
}
do {
try someFunction()
} catch CustomError.someError {
print("Caught a specific Error: CustomError.someError")
} catch {
print("Unknown Error \(error)")
}

Throwing Function — We can throw errors using the throwing functions - the "throws" keyword or use the "throw" keyword inside the block.

enum CustomError: Error {
case someError(message: String)
}
func someFunction() throws {
let randomNum = Int.random(in: 0...1)
if randomNum == 0 {
throw CustomError.someError(message: "Error A Occurred")
} else {
throw CustomError.someError(message: "Error B Occurred")
}
}
try someFunction()

try — We can use the try function before a function throws an error to indicate that aware of a potential error and how we can handle it.

enum CustomError: Error {
case someError
}
func someFunction() throws -> Int {
let randomNum = Int.random(in: 0...1)
if randomNum == 0 {
throw CustomError.someError
} else {
return 100
}
}

do {
try someFunction()
} catch CustomError.someError {
print("Caught a specific Error: CustomError.someError")
} catch {
print("Unknown Error \(error)")
}

try! — We shouldn’t use this function unless we are sure that the function won’t throw any error.

enum CustomError: Error {
case someError
}
func someFunction() throws -> Int {
let randomNum = Int.random(in: 0...1)
if randomNum == 0 {
throw CustomError.someError
} else {
return 100
}
}
let result = try! someFunction()
print("Result \(result)")

try? — Optional but it can contain a response or error. This will disable the catch block and if any error occurs, it will just return nil.

enum CustomError: Error {
case someError
}
func someFunction() throws -> Int {
let randomNum = Int.random(in: 0...1)
if randomNum == 0 {
throw CustomError.someError
} else {
return 100
}
}
let result = try? someFunction()
print("Result \(result ?? 0)")

Access Specifiers

Access specifiers are known for the visibility and accessibility of class members, structures, and enums.

Before going to the access specifiers, we must know the following basic things about the iOS Application.

  1. Module
  2. Framework
  3. Source File
  4. Target
  5. Bundle

Module — Single unit of code distribution. Imported by using the import keyword.

Target — App bundle or Framework called a separate Module

Source File — Single source file within the same module or the framework or app

Bundle — A Collection of files that make up a build app. Files made up with ipa file

Access Specifiers — used to control the visibility and
accessibility of classes, structures, enums, properties, and methods.

Five different Access levels available in Swift are:

  1. Open
  2. Public
  3. Internal
  4. file private
  5. Private
  6. Final

Open

  1. Most Permissive Access Level.
  2. Can be accessed from any source file from any module or target or
    framework.
  3. Can be subclassed or overridden by external modules.
import UIKit

// Module
class SomeClass {
var tableView: UITableView = UITableView()
}

// From Apple Documentation
open class UITableView : UIScrollView, NSCoding, UIDataSourceTranslating {

}

// Example
open class MyClass {
open var property: Int = 0
open func someFunc() {
}
}

// This will throw an error as we cannot have open structure.
// Replace 'open' with 'struct'
open struct MyStruct {

}

Public

  1. Similar to the Open Access level but with some limitations.
  2. Can be accessed from any source file from any module or target or framework.
  3. Cannot be subclassed or overridden by external modules.

For example, we can try public by using the UIKit framework

public class SomeButtonView: UIButton {
public func setButtonTitle(_ title: String) {
setTitle(title, for: .normal)
}
}

Internal

  1. Default Access Level in Swift.
  2. Can be accessed from any source file from the same module or target or framework but cannot be done from external modules.
  3. Useful for defining internal implementation details.
// Internal class and internal functions
internal class InternalViewController: UIViewController {
internal override func viewDidLoad() {
super.viewDidLoad()
setupUI()
}
private lazy var label: UILabel = {
let label = UILabel(frame: CGRect(x: 0, y: 0, width: 200, height: 200))
label.text = "Internal Label View"
label.textAlignment = .center
label.font = .systemFont(ofSize: 12, weight: .bold)
label.numberOfLines = 1
label.textColor = .blue
label.sizeToFit()
return label
}()
private func setupUI() {
view.addSubview(label)
}
}

file private

  1. Can be accessed from within the same source file.
  2. Useful for hiding implementation details in a single source file.

Please look into an example of fileprivate and private in same file.

class Employee {
fileprivate var firstName: String
private var nickName: String
init (firstName: String, nickName: String) {
self.firstName = firstName
self.nickName = nickName
}
fileprivate func updateFirstName(){}
private func updateNickName() {}
}
class FetchRecords: Employee {
func getEmployee() -> String {
updateFirstName() // Accessible
return firstName // Accessible
}
func getAnotherEmployee() -> String {
updateNickName() //'updateNickName' is inaccessible due to 'private' protection level
return nickName // 'nickName' is inaccessible due to 'private' protection level
}
}
extension Employee {
fileprivate func modifyName() {
print("Employee Name is \(firstName)") // Accessible
print("Employee Nick Name is \(nickName)") // Accessible
}
}
var employee = Employee(firstName: "Sabapathy", nickName: "Saba")
employee.modifyName()

Private

  1. Most Restricted Access Level.
  2. Can be accessed from within the declaration or extensions of the same source file.
  3. Used for Encapsulating the implementation details within a specific scope.

Please look into an example of fileprivate and private in different file.

// Main.swift
class Employee {
fileprivate var firstName: String
private var nickName: String
init (firstName: String, nickName: String) {
self.firstName = firstName
self.nickName = nickName
}
fileprivate func updateFirstName(){}
private func updateNickName() {}
}

// Extension.swift
extension Employee {
fileprivate func modifyName() {
print("Employee Name is \(firstName)")
// name is inaccessible because of 'file-private' protection level
print("Employee Nick Name is \(nickName)")
// nickName is inaccessible because of 'private' protection level
}
}

Open vs Public

  1. Open — Applies to class and class members but not structures.
  2. Can access, subclass, and override the class or class members outside the defined module.
  3. Public — applies to class, structures, and enums and their members.
  4. Can access but not subclassing or overriding outside the defined module.

When can we use Open or Public?

  1. Use Open when we design a public API where others can extend it and modify the implementation outside the module.
  2. Use Public when other modules can access them but not
    extend or modify them.

When to use Internal?

  1. Internal plays an important role when we create a framework and will not allow other modules/frameworks to access the entities.
  2. Another good example is when we work on large-scale projects with multiple modules/frameworks.

When to use File-Private and Private?

  1. Use private when we have a data model that contains user information. Thus, it will prevent modifying the data.
  2. Use file-private for utility classes or helper classes. This will help in hiding the implementation details and prevent accessing or relying on them.

Don’t forget about the Final in Swift

Use final when you do the following

  1. Prevent the class in the framework for subclassing.
  2. Other than class, we can mark for properties and methods.
  3. Static Dispatch can be achieved and the performance will be increased.
  4. We can use it to prevent overriding the methods in the framework and avoid issues.

Architectural Patterns

Higher Order Functions in Swift

Functional Programming — Code empowers to handle functions as essential building blocks. Manipulate functions and extract useful outcomes from them.

Higher Order functions

  • map
  • filter
  • reduce
  • compactMap
  • sorted
  • ForEach
  • flatMap

What is Transform

A Mapping closure that accepts and returns a transformed value of the same or a different type.

map — Returns an array by applying mapping closure to each element of the sequence.

An array containing the transformed elements of this sequence.

let firstArr = ["Jones", "Theodore", "Saba", "Pathy"]
let mapArr = firstArr.map { element in
element.lowercased()
}
print(mapArr)

Example with Model

struct Employee {
let name: String
let age: Int
}
let empArr = [
Employee(name: "Saba", age: 30),
Employee(name: "Pathy", age: 30)
]
let employees = empArr.map { $0.name }
print(employees)
// ["Saba", "Pathy"]

flatMap — Use to receive a single collection or sequence. Flattened Array

Complexity — O(m+n)

n = sequence length and m = result length

Works well with Optionals

s.flatMap(transform) = Array(s.map(transform).joined())

let optionalNum: [Int]? = [1,2,3,4,5]
let flatOptionalNum = optionalNum.flatMap { $0 }
print(flatOptionalNum)
// Optional(11,2 ,3 ,4 ,51)

compactMap — Returning an array of non-nil elements of transform with each element of Sequence. Resulting non-optional elements.

Complexity — O(n)

letpossibleNumbers =「"1","2","three","///4///","'5"]
let compactMapped: [Int] = possibleNumbers.compactMap { str in Int(str) }
print (compactMapped)
// [1, 2, 5]

Useful working with Optionals.

Usefulworkingw i t hOptionals
let optionalValues = ["1", "2", nil , nil, "5"]
let compactValues = optionalValues.compactMap { $0 } print(compactValues)

reduce — Returns result from combining the elements of the sequence using the given closure.

func reduce<Result>(
_ initialResult:Result,
_ nextPartialResult:(Result,Self.Element) throws → Result
) rethrows- >Result

If the sequence has no elements, the result is the Initial Result.

let numbers = [1, 2, 3, 4]
let numberSum = numbers.reduce(0, { x, y in
x + y
})
print(numberSum)

filter — Filtering the array of elements by satisfying the requirements. Parameter — isIncluded

let names = ["Jones", "saba", "Kanagasabapathy", "Rajkumar"]
let filterNames = names.filter { $0.hasPrefix("s") }
print(filterNames)

Works with compactMap and Optionals

let optionalNums = [1,2,nil,3,4,5,nil, nil]
let filterNums = optionalNums.compactMap { $0 }.filter { $0 > 4}
print(filterNums)

sorted — Sorting array of sequence’s elements.

Complexity — O(n log n)

Works well when Element conforms to Comparable Protocol.

let a = [1,2,3,21,23,20,100,50]
print(a.sorted())
let b = ["Adam", "John", "Saba", "Alan", "Rowe"]
print(b.sorted())

sorted(by:)

array in Increasing Order —

let lastArr = ["Kofi", "Anna", "Peter", "Charlie", "Chaplin"]
print(lastArr.sorted(by: <))
//["Anna", "Chaplin", "Charlie", "Kofi", "Peter"]
print(lastArr.sorted(by: >))
//["Peter", "Kofi", "Charlie", "Chaplin", "Anna"]

forEach — Similar to a for-in loop but cannot break or continue and return will exit from the current call, not from the scope.

let arr = ["Kofi", "Anna", "Peter", "Charlie", "Chaplin"]
arr.forEach { name in
print(name)
}

Differences

Transforms

map — produces a collection.

compactMap — filters out nil values and resulting non-optional

flatMap — flattens the results, allowing for a different type.

reduce — combines all elements into a single value using a closure.

filter — filters based on a condition, producing a collection of the same type.

Iteration

forEach — Applies a closure to each element for side effects without producing a new collection.

Swift Basics

Tricky example

let json = """
{
"testArr": [
{
"listDate": "2021-08-23",
"subTitle": "dmuAndSyncBuffer Workfow",
"mainTitle": "Kanagasabapathy",
"iconUrl": "defaultInstanceListIcon",
"priority": [
{
"listDate": "2021-08-23",
"subTitle": "dmuAndSyncBuffer Workfow",
"mainTitle": "Kanagasabapathy",
"iconUrl": "defaultInstanceListIcon",
"priority": 0
}
]
},
{
"listDate": "2021-08-25",
"subTitle": "dmuAndSyncBuffer Workfow",
"mainTitle": "Pathy",
"iconUrl": "defaultInstanceListIcon",
"priority": [
{
"listDate": "2021-08-23",
"subTitle": "dmuAndSyncBuffer Workfow",
"mainTitle": "Kanagasabapathy",
"iconUrl": "defaultInstanceListIcon",
"priority": 0
}
]
}
]
}
"""
// MARK: - TestData
struct TestData: Codable {
var testArr: [TestArr]
}

// MARK: - TestArr
struct TestArr: Codable {
var listDate, subTitle, mainTitle, iconURL: String
let priority: [Priority]

enum CodingKeys: String, CodingKey {
case listDate, subTitle, mainTitle
case iconURL = "iconUrl"
case priority
}
}

// MARK: - Priority
struct Priority: Codable {
var listDate, subTitle, mainTitle, iconURL: String
let priority: Int

enum CodingKeys: String, CodingKey {
case listDate, subTitle, mainTitle
case iconURL = "iconUrl"
case priority
}
}

Decode and rename the value of the specific parameter

let data =  json.data(using: .utf8)
do {
let decoder = JSONDecoder()
let jsonData = try decoder.decode(TestData.self, from: data!)
print(jsonData.testArr)
let newData = jsonData.testArr.map { arr in
var newArr = arr
if arr.mainTitle == "Kanagasabapathy" {
newArr.mainTitle = "SABA"
}
return newArr
}
print("\n Updated Data \(newData)")
} catch {
fatalError("Error \(error)")
}

Networking

FAQ — Difference b/w OperationQueue vs GCD

GCD vs OperationQueues

Grateful for your read, now let’s code on!

Interested in connecting? 
Feel free to connect with me on: LinkedIn and GitHub

Stackademic

Thank you for reading until the end. Before you go:

  • Please consider clapping and following the writer! 👏
  • Follow us on Twitter(X), LinkedIn, and YouTube.
  • Visit Stackademic.com to find out more about how we are democratizing free programming education around the world.

--

--

Kanagasabapathy Rajkumar

Swift Enthusiast | Building Seamless iOS Experiences 🚀 | Swift & Objective-C |