Architecture iOS App - Imtiaz211/interviews GitHub Wiki

MVC Architecture?

Main advantage of MVC architecture is to provide reusability and security by separating the layer by using MVC architecture. The Model View Controller (Commonly known as MVC) framework helps you to build applications that are easier to test and maintain it comprises of three major components, namely

  1. Model: This is the layer that represents the application’s data.
  2. View: This represents the presentation or the user interface layer.
  3. Controller: This layer typically contains the business logic of your application.

In the case of MVC it is controller, in the case of MVP it is presenter, in case of MVVM it is view model. MVVM facilitates a separation of development of the graphical user interface.

MVP Architecture ?

M: This is the layer that represents the application’s data. V: View P: Presenter -> The presenter contains all ui logics. The presenter is also decouple directory from the view and talk to it through an interface.

MVVM Architecture ?

M: This is the layer that represents the application’s data. V: view its like Viewcontroller that have all UI related stuff maintain in view hidden or unhidden. VM: view model (MVVM) is a software architectural pattern. is layer is responsible for all business logic, network layer etc.

VIPER Architecture

V: View -> The responsibility of the view is to send the user actions to the presenter and show whatever the presenter tells it. I: Interactor -> This is the backbone of an application as it contains the business logic. P: Presenter -> Its responsibility is to get the data from the interactor on user actions and after getting data from the interactor,it sends it to the view to show it. It also asks the router/wireframe for navigation. E: Entity -> It contains basic model objects used by the Interactor. R: Router -> It has all navigation logic for describing which screens are to be shown when. It is normally written as a wireframe. This architecture is based on Single Responsibility Principle which leads to a clean architecture.

VIP Architecture (one way directional) V = View I = Interactor P = Presentor Design Pattern

[!IMPORTANT] Design patterns are reusable solutions to common problems in software design. They're templates designed to help you write code that's easy to understand and reuse

  1. Coordinator Pattern: The coordinator pattern is a structural design pattern for organizing flow logic between view controllers.
  2. Singleton Pattern: Singleton is a creational design pattern, which ensures that only one object of its kind exists and provides a single point of access to it for any other code. Singleton has almost the same pros and cons as global variables.
  3. Delegation Pattern: Delegates are a design pattern that allows one object to send messages to another object when a specific event happens. Imagine an object A calls an object B to perform an action.
  4. Observer pattern: Observer is a behavioral design pattern that allows some objects to notify other objects about changes in their state. The Observer pattern provides a way to subscribe and unsubscribe to and from these events for any object that implements a subscriber interface.

SOLID Principles of Object-Oriented Programming

  1. Single Responsibility Principle = A class should do one thing and therefore it should have only a single reason to change.
class Handler { 
    let apiHandler: APIHandler 
    let parseHandler: ParseHandler 
    let databaseHandler: DBHandler 
    init(apiHandler: APIHandler, parseHandler: ParseHandler, dbHandler: DBHandler) { 
        self.apiHandler = apiHandler 
        self.parseHandler = parseHandler 
        self.dbHandler = dbHandler 
    } 
    func handle() { 
        let data = apiHandler.requestDataToAPI() 
        let array = parseHandler.parse(data: data)
        databaseHandler.saveToDatabase(array)
    } 
} 
class NetworkHandler { 
    func requestDataToAPI() -> Data { 
        // Network request and wait the response 
    } 
}
class ResponseHandler { 
    func parseResponse(data: Data) -> [String] { 
        // Parse the network response into array 
    } 
}
class DatabaseHandler { 
    func saveToDatabase(array: [String]) { 
        // Save parsed response into database
    } 
}
  1. Open-Closed Principle = Requires that classes should be open for extension and closed to modification.
protocol Printable {
    func printDetails() -> String
}
class Car: Printable { 
    let name: String 
    let color: String
    init(name: String, color: String) {
        self.name = name
        self.color = color
    }
    func printDetails() -> String {
        return "I have \(self.color) color \(self.name)."
    }
}
class Bike: Printable {
    let name: String
    let color: String
    init(name: String, color: String) {
        self.name = name
        self.color = color
    }
    func printDetails() -> String {
        return "I have \(self.name) bike of color \(self.color)."
    }
}
class Logger {
    func printData() {
        let vehicles: [Printable] = [Car(name: "BMW", color: "Red"),
                                  Car(name: "Audi", color: "Black"),
                            Bike(name: "Honda CBR", color: "Black"),
                              Bike(name: "Triumph", color: "White")]
        vehicles.forEach { vehicle in
            print(vehicle.printDetails())
        }
    }
}
  1. Liskov Substitution Principle = States that subclasses should be substitutable for their base classes.
class Operators {
    func add(num1: Int, num2: Int) -> Int{
        return num1 + num2
    }
    
    func sub(num1: Int, num2: Int) -> Int{
        return num1 - num2
    }
}

class Calculator: Operators {
    override func add(num1: Int, num2: Int) -> Int {
        return num1 + num2
    }
    
    override func sub(num1: Int, num2: Int) -> Int {
        return num1 - num2
    }
    
    func add(num1: Int, num2: Int, num3: Int) -> Int{
        return num1 + num2 + num3
    }
}

let add = Operators()
print(add.add(num1: 5, num2: 5)) // cool works -> 10

let calc = Calculator()
print(calc.add(num1: 5, num2: 5)) // cool works -> 10

// also added a new function

print(calc.add(num1: 2, num2: 5, num3: 6))
  1. Interface Segregation Principle = Segregation means keeping things separated, and the Interface Segregation Principle is about separating the interfaces.
protocol Flyable {
    func fly()
}

protocol Swimmable {
    func swim()
}

protocol Feedable {
    func eat()
}

class Flamingo: Flyable, Swimmable, Feedable  {
    func eat() {
        print("I can eat")
    }
    
    func fly() {
        print("I can fly")
    }
    
    func swim() {
        print("I can swim")
    }
}

class Dogs: Feedable {
    func eat() {
        print("I can eat")
    }
}
  1. Dependency Inversion Principle = States that our classes should depend upon interfaces or abstract classes instead of concrete classes and functions.
// Abstraction: Animal
protocol Animal {
    func makeSound()
}

// Low-level class: Dog
class Dog: Animal {
    func makeSound() {
        print("Woof!")
    }
}

// Low-level class: Cat
class Cat: Animal {
    func makeSound() {
        print("Meow!")
    }
}

// High-level class: AnimalSoundMaker
class AnimalSoundMaker {
    let animal: Animal
    
    init(animal: Animal) {
        self.animal = animal
    }
    
    func performSound() {
        animal.makeSound()
    }
}

Principles of Software Engineering

  1. KISS (Keep It Simple, Stupid) = states that codes should be as simple as possible without a complicated structure, otherwise debugging and maintenance might be more difficult
  2. DRY (Don’t Repeat Yourself) = states that we shouldn’t repeat the same thing too many times in too many places.
  3. YAGNI (You Aren’t Gonna Need It)
  4. BDUF (Big Design Upfront)
  5. SOLID
  6. Occam’s Razor
  7. Law of Demeter
  8. Principle of Least Astonishment
  9. Measure Twice and Cut Once
  10. Avoid Premature Optimization

MVC and MVVM difference

  1. MVVM
    • This architecture pattern is more event-driven as it uses data binding and thus makes easy separation of core business logic from the View.
    • Multiple View can be mapped with a single ViewModel and thus, the one-to-many relationship exists between View and ViewModel.
    • The View has references to the ViewModel
    • Not ideal for small scale projects.
    • Unit testability is highest in this architecture.
  2. MVC
    • Limited support to Unit testing.
    • Ideal for small scale projects only.
    • The View has no knowledge about the Controller.
    • Controller and View exist with the one-to-many relationship. One Controller can select a different View based upon required operation.
    • UI(View) and data-access mechanism(Model) are tightly coupled.

The different resolution requires different image versions like

  1. @2x (iPhone 4, 4s, 5, 6, 6s, 7, 7s, 8, XF), @3x (Plus size iPhones, X, Xs, XS Max).
  2. armv6 -> Older iPhones
  3. armv7 -> iPhone 4, 4S
  4. armv7s -> iPhone 5, 5C
  5. arm64 -> iPhone 5s and later.

[!IMPORTANT] The flash storage in an iOS device is faster than a traditional hard disk, but still around 200 times slower than RAM,