美文网首页
iOS | VIP Design Pattern

iOS | VIP Design Pattern

作者: 清無 | 来源:发表于2022-02-08 11:14 被阅读0次

    Brief

    What does VIP stand for then? View – Interactor – Presenter.

    The VIP architecture for writing clean Swift code was introduced by Raymond Law. He created a clean-swift website where you can read about how to use VIP pattern in UIKit.

    What Is VIP?

    VIP is an architectural pattern like MVC, MVP or MVVM, MVI(Model-View-Intent). Its main difference is the clear logic separation between its components. VIP was created to fix MVC, or Massive View Controllers, a common problem in UIKit apps where View Controllers become the main object where code is kept and they become Massive in that most if not all of your logic is kept within them. This can also cause problems when testing your code.

    VIP
    • The View is your app’s UI. This corresponds to a SwiftUI View. It sends requests to the interactor every time the user interacts with the UI.
    • The Interactor handles your app’s business logic, such as fetching data from the network or saving data in a database. When the view requests something, the interactor does the processing and sends the result as a response to the presenter.
    • The Presenter handles the presentation logic. It formats the received data into view models suitable for display and then passes it to the view.

    Xcode Files Groups

    Folders

    Models contains your domain’s model that you use across the scenes and isn’t tied to any specific scene. Each scene will have its scene-specific model that you’ll add later.

    Scenes contains all the scenes for your domain. A scene normally is a single screen or collection of screens for a feature. ScoopsAndScones has a single scene called CreateIceCream.

    VIP

    VIP Flow

    The view creates a Request object and sends it to the interactor. The interactor takes the request object, performs work and sends the result as a Response to the presenter. The presenter then takes the response, formats the data into primitive types and sends the result as a ViewModel back to the view.

    Creating a Model

    enum CreateIceCream {
      enum LoadIceCream {
        struct Request {}
    
        struct Response {
          var iceCreamData: IceCream
        }
    
        struct ViewModel {
          var cones: [String]
          var flavors: [String]
          var toppings: [String]
        }
      }
    }
    

    LoadIceCream wraps the data model and represents a single functionality of your code, loading the ice cream and showing it in the view.

    If the app had extra logic such as saving or deleting the data, you’d create separate enums called SaveIceCream and DeleteIceCream. Both of them would then have their own data models.

    let request = CreateIceCream.LoadIceCream.Request()
    

    Setting Up the View

    var interactor: CreateIceCreamBusinessLogic?
    

    This links the interactor with the view through the CreateIceCreamBusinessLogic protocol.

    Components communicate with each other through protocols. This makes each component of a scene less tightly tied to other components. The view asks the interactor to perform the business logic but doesn’t know how it’s done.

    func fetchIceCream() {
      let request = CreateIceCream.LoadIceCream.Request()
      interactor?.loadIceCream(request: request)
    }
    

    Setting Up the Interactor

    Create a Swift File named CreateIceCreamInteractor.swift in the CreateIceCream group.

    protocol CreateIceCreamBusinessLogic {
      func loadIceCream(request: CreateIceCream.LoadIceCream.Request)
    }
    
    class CreateIceCreamInteractor {
      var presenter: CreateIceCreamPresentationLogic?
    }
    

    As already mentioned, protocols allow you to decouple your components. The interactor passes the response to the presenter but doesn’t know who’s presenting the data or how.

    extension CreateIceCreamInteractor: CreateIceCreamBusinessLogic {
      func loadIceCream(request: CreateIceCream.LoadIceCream.Request) {
        // TODO
      }
    }
    

    Presenting the Response

    let iceCream = Bundle.main.decode(IceCream.self, from: "icecream.json")
    let response = CreateIceCream.LoadIceCream.Response(iceCreamData: iceCream)
    presenter?.presentIceCream(response: response)
    

    The interactor is your app’s brain and handles all the business logic such as loading, deleting or saving the data. But there’s another component you could add to the interactor, called Worker.

    VIP Flows

    You can have multiple workers for the interactor, with each handling a specific logic. If your app fetched the data from an API, you’d create a NetworkWorker and have all the networking logic inside. If your app saved the data using CoreData, you’d add a CoreDataWorker and so on.

    Setting Up the Presenter

    Create a Swift File named CreateIceCreamPresenter.swift in the CreateIceCream group.

    protocol CreateIceCreamPresentationLogic {
      func presentIceCream(response: CreateIceCream.LoadIceCream.Response)
    }
    
    class CreateIceCreamPresenter {
      var view: CreateIceCreamDisplayLogic?
    }
    
    extension CreateIceCreamPresenter: CreateIceCreamPresentationLogic {
      func presentIceCream(response: CreateIceCream.LoadIceCream.Response) {
        // TODO
      }
    }
    

    Sending ViewModel to View

    let viewModel = CreateIceCream.LoadIceCream.ViewModel(
      cones: response.iceCreamData.cones,
      flavors: response.iceCreamData.flavors,
      toppings: response.iceCreamData.toppings
    )
    view?.displayIceCream(viewModel: viewModel)
    

    Creating a Display Logic Protocol

    protocol CreateIceCreamDisplayLogic {
      func displayIceCream(viewModel: CreateIceCream.LoadIceCream.ViewModel)
    }
    

    Adding a Configurator

    You’ve created all the components, but you need to create instances of the presenter and interactor and connect them using a Configurator.

    The configurator’s job is to instantiate and connect the components of the VIP cycle. This is where you create the unidirectional cycle between the VIP components. There’s only one configurator for every scene and you need to call it only once, so you’ll create it in a separate file.

    Create a Swift File named CreateIceCreamConfigurator.swift in the CreateIceCream group.

    extension CreateIceCreamView {
      func configureView() -> some View {
        var view = self
        let interactor = CreateIceCreamInteractor()
        let presenter = CreateIceCreamPresenter()
        view.interactor = interactor
        interactor.presenter = presenter
        presenter.view = view
    
        return view
      }
    }
    

    configureView() creates instances of the interactor and presenter and assigns the corresponding references.

    Now, all you have to do is call the function on the view.

    Open ContentView.swift and replace CreateIceCreamView() with:

    CreateIceCreamView().configureView()
    

    相关文章

      网友评论

          本文标题:iOS | VIP Design Pattern

          本文链接:https://www.haomeiwen.com/subject/efkbkrtx.html