Viper Framework for iOS using Swift

Overview

Viperit

Language Build Status Platform License Codecov codebeat badge CocoaPods Carthage Compatible Accio Swift Package Manager compatible SwiftUI compatible

Write an iOS app following VIPER architecture. But in an easy way.

Viper the easy way

We all know Viper is cool. But we also know that it's hard to setup. This library intends to simplify all that boilerplate process. If you don't know yet what Viper is, check this out: Architecting iOS Apps with VIPER (objc.io)

Installation

Requirements

  • iOS 11.0+
  • Swift 5.1+
  • Xcode 11.0+

Swift Package Manager (SPM)

You can easily install this framework using SPM on Xcode. Go to File | Swift Packages | Add Package Dependency... in Xcode and search for "http://github.com/ferranabello/Viperit"

CocoaPods

CocoaPods is a dependency manager for Cocoa projects.

Specify Viperit into your project's Podfile:

source 'https://github.com/CocoaPods/Specs.git'
platform :ios, '11.0'
use_frameworks!

pod 'Viperit'

Carthage

Carthage is a decentralized dependency manager that builds your dependencies and provides you with binary frameworks.

To integrate Viperit into your Xcode project using Carthage, specify it in your Cartfile:

github "ferranabello/Viperit"

Run carthage update to build the framework and drag the built Viperit.framework into your Xcode project.

Features

Create modules easily using Xcode templates

Viperit Xcode templates can be downloaded from the latest release page. Download the Templates.zip file.

To install them, unzip the file, open your terminal and run:

cd PATH/TO/UNZIPPED/FOLDER
mkdir -p ~/Library/Developer/Xcode/Templates/
cp -R Viperit ~/Library/Developer/Xcode/Templates/

Module Creation

You can check "Also create a Storyboard file for module" if you want the storyboard file to be automatically created for you. Choose between "Universal" to use just one view for phones and tablets, and "Dedicated Tablet View" if you want to have a separated view for tablet devices.

Use storyboard, xib, programmatic views or SwiftUI

Any Viperit module will assume its view is loaded from a Storyboard by default. But you can use storyboards, nibs, code or even SwiftUI views! All you need to do is to override the variable viewType in your modules enum:

enum MySuperCoolModules: String, ViperitModule {
    case theStoryboardThing  
    case oldSchool
    case xibModule
    case whatTheSwift

    var viewType: ViperitViewType {
        switch self {
        case .theStoryboardThing: return .storyboard
        case .oldSchool: return .code
        case .xibModule: return .nib
        case .whatTheSwift: return .swiftUI
        }
    }
}

Built-in router functions

This framework is very flexible, it's meant to be used in any way you want, but it has some useful built-in functionalities in the router that you could use:

    //Show your module as the root view controller of the given window
    func show(inWindow window: UIWindow?, embedInNavController: Bool, setupData: Any?, makeKeyAndVisible: Bool)

    //Show your module from any given view controller
    func show(from: UIViewController, embedInNavController: Bool, setupData: Any?)

    //Show your module inside another view
    func show(from containerView: UIViewController, insideView targetView: UIView, setupData: Any?)

    //Present your module modally
    func present(from: UIViewController, embedInNavController: Bool, presentationStyle: UIModalPresentationStyle, transitionStyle: UIModalTransitionStyle, setupData: Any?, completion: (() -> Void)?)

Easy to test

You can test your module injecting mock layers like so:

    var module = AppModules.home.build()
    view = HomeMockView()
    view.expectation = expectation(description: "Test expectation")
    module.injectMock(view: view)
    ...

Usage

Now, let's create our first Viperit module called "myFirstModule"!

0. Create your module files

Let's use the provided Xcode template to easily create all the needed classes for the module. Just click New file in the document panel and choose between Protocol-oriented module, Object-oriented module or SwiftUI module under the "Viperit" section.

1. Create a modules enum

You need at least one (you can use as many as you like, maybe to group modules by functionality) enum that implements the ViperitModule protocol to enumerate your application modules.

import Viperit

//MARK: - Application modules
enum AppModules: String, ViperitModule {
    case myFirstModule
}

2. Build the module and perform navigation

Imagine this is a new app and we want to load our "myFirstModule" module as the app's startup module

import Viperit

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
    var window: UIWindow?

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
        window = UIWindow(frame: UIScreen.main.bounds)
        let module = AppModules.myFirstModule.build()
        let router = module.router as! MyFirstModuleRouter
        router.show(inWindow: window)
        return true
    }
}

This is just an example, you could of course use your own router functions instead of the provided show(inWindow:):

    window = UIWindow(frame: UIScreen.main.bounds)
    let module = AppModules.myFirstModule.build()
    let router = module.router as! MyFirstModuleRouter
    router.mySuperCoolShowFunction(inWindow: window)

2.1. Are you using SwiftUI?

Let's say you created a module based on SwiftUI called 'Cool'. All you need to do is to use the new Viperit SwiftUI module builder:

import SwiftUI
import Viperit

//A sample function that could be implemented in some Router to show your Cool SwiftUI module
//You can even inject an @EnvironmentObject view model to your SwiftUI view.
func showTheCoolModule() {
  let module = AppModules.cool.build { presenter -> (CoolView, UserSettings) in
      let p = presenter as! CoolPresenterApi
      let settings = p.settings()
      return (CoolView(presenter: p), settings)
  }
  let router = module.router as! CoolRouter
  router.show(from: viewController)
}

Check the example app to have a better understanding of how it works, and how to manage data flow on SwiftUI with the presenter.

3. Follow the Viper flow

Everything is ready for you to make great things the Viper way! Clone the repo and run the 'Example' target to see it in action! Or just try it with Cocoapods:

pod try Viperit

Author

Ferran Abelló

License

Viperit is released under MIT license and copyrighted by Ferran Abelló.

Comments
  • SwiftUI weak linking

    SwiftUI weak linking

    Do you think it is possible to add availability for SwiftUI features in framework? I accidentally run into crash because of that :( Sth like #if isAvailable() or version check might be helpful :)

    My failure was

    dyld: Library not loaded: /System/Library/Frameworks/SwiftUI.framework/SwiftUI Referenced from: /Users/piotrgawlowski/Library/Developer/CoreSimulator/Devices/818027B6-FE01-489E-937A-E7764561A2CE/data/Containers/Bundle/Application/D9182AB1-13FE-40CE-A395-45E6B06EA2F4/eForskrivning.app/Frameworks/Viperit.framework/Viperit Reason: image not found

    opened by pgawlowski 6
  • AppModule.build() crashes app

    AppModule.build() crashes app

    I've set optimization level "optimize for speed".

            let module = module.build()        
            module.router.show(from: viewController, embedInNavController: true, setupData: id)
    
    

    embedInNavController: true seems to be crucial here.

    I am calling router.show() with already existing navigation controller to archive card like presentation style with different navigation context.

    In that situation app crashes because of nil _preseter. With optimization for speed turned off everything seems to be fine.

    Any ideas how to handle? Currently I've turned off optimization.

    opened by pgawlowski 4
  • Fix class name for Viper component in Application Module generic enum

    Fix class name for Viper component in Application Module generic enum

    I made a sample project named "Viper-Sample" and the Viper components created belong to "Viper_Sample" bundle namespace. So this fixes the classForViperComponent method returning nil.

    opened by moux2003 4
  • add modally present and test

    add modally present and test

    WHAT WAS ADDED ? A modal presentation style has been added to show the view controller. Unit test was also added. FOR WHAT WAS ADDED ? This feature was necessary for the modal presentation display of controllers on the guidelines of Apple. Without this, you need to do the Router extension.

    opened by sergiusKurganov 4
  • ViperIt unable to compile with Xcode 13

    ViperIt unable to compile with Xcode 13

    class HostingUserInterface - file UserInterface+SwiftUI.swift line 16 Incorrect argument labels in call (have 'nibName:bundle:', expected 'coder:rootView:')

    opened by Speakus 3
  • Viperit: Unexpectedly found nil while implicitly unwrapping an Optional value

    Viperit: Unexpectedly found nil while implicitly unwrapping an Optional value

    There's an issue that happens only when downloading the app from testflight, otherwise running from Xcode works fine and I don't use storyboard or xib files it's only code

    Screen Shot 2021-07-11 at 11 34 37 AM

    And here's the implementation

    window = UIWindow(windowScene: scene)
    let module = AppModules.splash.build()
    module.router.show(inWindow: window, embedInNavController: false, setupData: nil, makeKeyAndVisible: true)
    
    opened by ahmedraad 3
  • Two questions

    Two questions

    Hi,

    interesting framework and library, I've two questions:

    • If I need a custom UIViewController what do I have to do? I've to create a custom UserInterface that inherits from my custom UIViewController? I've seen that UserInterface inherits from UIViewController. Here (https://github.com/ferranabello/Viperit/issues/69) you say that we have to thins Eureka as a subview but it complicates things. If we want to simplify could we create a custom UserInterface. Could you give us an example?

    • In you framework there's DisplayData. How should it be used?

    Thanks

    question 
    opened by mapo80 3
  • Modules integration

    Modules integration

    Hi! First of all - thank you for great framework! What is the best practice of integration of one module into another? E.g: ParentModule contains table, and the ChildModule contains view for ParentModule tableHeaderView. What is the proper way to integrate ChildModule into ParentModule? Thank you!

    question 
    opened by BorysShcherbyna 3
  • Alamofire API Request

    Alamofire API Request

    Could I get the sample format with Alamofire in Viperit like iOS-Viper-Architecture. And How do I create the storyboard for iPad and iPhone within one module because iPad and iPhone was difference Design? Thanks a lot.

    opened by tharhtet 3
  • App crashes run time

    App crashes run time

    I have build a project according to viperit instructions then app crashes on the start .That can be seen in screen shot .Here is my AppDelegate source ` import UIKit import Viperit enum AppModules: String, ViperitModule { case myFirstModule } @UIApplicationMain class AppDelegate: UIResponder, UIApplicationDelegate {

    var window: UIWindow?
    
    
    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
        
        window = UIWindow(frame: UIScreen.main.bounds)
        let module = AppModules.myFirstModule.build()
        module.router.show(inWindow: window)
        return true
    }
    

    ` screen shot 2017-09-28 at 11 14 56 am

    opened by mubasherkhan 3
  • Apply SwiftLint

    Apply SwiftLint

    First of all let me congratulate you, this is the best approach to VIPER I have seen and it's close to mine but using a bigger knowledge on Swift.

    But it doesn't compile against https://github.com/realm/SwiftLint , i can exclude your Pod from the listing process but as i rather to understand your source would be cooler if it were linted.

    Even excluding Pods from the linting, the modules generated by the template includes at least two lint errors that could be easily fixed:

    • the forced casts on VIPER componentes getters var presenter: LoginPresenter { return _presenter as! LoginPresenter }
    • the use of underscore on the same VIPER componentes, on my VIPER architecture I called them proxyPresenter, proxyRouter...
    opened by buguibu 3
  • Build storyboard issue

    Build storyboard issue

    Fatal error: Unexpectedly found nil while unwrapping an Optional value: file /Users/chris/Nutstore Files/XCode/VIPER/ViperItExample/Pods/Viperit/Viperit/Core/Module.swift, line 28 2020-06-13 12:05:39.324354+0800 ViperItExample[2698:112714] Fatal error: Unexpectedly found nil while unwrapping an Optional value: file /Users/chris/Nutstore Files/XCode/VIPER/ViperItExample/Pods/Viperit/Viperit/Core/Module.swift, line 28

    func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) { // Use this method to optionally configure and attach the UIWindowwindowto the provided UIWindowScenescene. // If using a storyboard, thewindowproperty will automatically be initialized and attached to the scene. // This delegate does not imply the connecting scene or session are new (seeapplication:configurationForConnectingSceneSession` instead).

    // guard let _ = (scene as? UIWindowScene) else { return }

        guard let scene = (scene as? UIWindowScene) else { return }
    
        window = UIWindow(frame: UIScreen.main.bounds)
        window?.windowScene = scene
    
        let module = AppModules.ceshi.build()
        let router = module.router as! CeShiRouter
        module.router.show(inWindow: window, embedInNavController: true, setupData: nil, makeKeyAndVisible: true)
        
    }`
    
    opened by chris-choy 1
  • One view, multiple modules

    One view, multiple modules

    Is it any neat way to use one view (storyboard/xib/whatever) with multiple modules? Example: We've got same, template style overlay view. Let's call it ActionOverlayView. It has always exactly same construction: header, description, button1, button2 etc. but totally different behaviour. Once it will redirect to different parts of app, other time it's going to resend verification email, logout user etc. There is totally no point of copy pasting whole view only for the same of module.

    That is why I think it might be useful to move viewIdentifier to ViperItModuleProtocol and allow us to change default viewIdentifier.

    VipertitModuleProtocol var viewIdentifier: String? { get }

    Module let viewIdentifier = module.viewIdentifier ?? safeString(NSStringFromClass(viewClass).components(separatedBy: ".").last)

    In that case we might be able to use one view with multi-purpose modules.

    opened by pgawlowski 0
Releases(1.5.0)
Owner
Ferran Abelló
iOS
Ferran Abelló
This repository contains a detailed sample app that implements VIPER architecture in iOS using libraries and frameworks like Alamofire, AlamofireImage, PKHUD, CoreData etc.

iOS Viper Architecture: Sample App This repository contains a detailed sample app that implements VIPER architecture using libraries and frameworks li

MindOrks 653 Jan 2, 2023
Sample project using VIPER architecture

VIPER-Persons Small project using a master and detail view Demonstrates the use of the following features: VIPER architecture (https://mutualmobile.co

Sebastian Wramba 43 Feb 11, 2022
A collection of iOS architectures - MVC, MVVM, MVVM+RxSwift, VIPER, RIBs and many others

ios-architecture WIP ?? ?? ?? ??️ Demystifying MVC, MVVM, VIPER, RIBs and many others A collection of simple one screen apps to showcase and discuss d

Pawel Krawiec 1.3k Jan 3, 2023
Swift Interaction with VIPER Architecture

SwiftyVIPER SwiftyVIPER allows easy use of VIPER architecture throughout your iOS application. VIPER Architecture What is VIPER? Great question! VIPER

Cody Winton 121 Jan 2, 2023
A Swift 4.2 VIPER Module Boilerplate Generator with predefined functions and a BaseViewProtocol.

Perfection is achieved, not when there is nothing more to add, but when there is nothing left to take away. Are you new to VIPER Design Pattern? Want

Mohamad Kaakati 68 Sep 29, 2022
Techcareer.net Bootcamp graduation project written with VIPER, highly inspired by Getir

götür Techcareer.net iOS Bootcamp'i bitirme projesi, Getir'den yüksek miktarda i

Kemal Sanlı 9 Dec 3, 2022
MoneySafe - Application for tracking income and expenses and analyzing expenses. VIPER architecture, CoreData, Charts

?? MoneySafe ?? Application for tracking income and expenses and analyzing expen

Vladislav 5 Dec 27, 2022
Sample applications of iOS Design patterns written using swift.

ios-design-patterns This repo contains all my Sample applications of iOS Design patterns written using swift. Link for my Design patterns Blog : https

ShreeThaanu Raveendran 3 Nov 2, 2022
Example of Clean Architecture of iOS app using RxSwift

Clean architecture with RxSwift Contributions are welcome and highly appreciated!! You can do this by: opening an issue to discuss the current solutio

null 3.6k Dec 29, 2022
SwiftUI sample app using Clean Architecture. Examples of working with CoreData persistence, networking, dependency injection, unit testing, and more.

Articles related to this project Clean Architecture for SwiftUI Programmatic navigation in SwiftUI project Separation of Concerns in Software Design C

Alexey Naumov 4k Dec 31, 2022
Reactant is a reactive architecture for iOS

Reactant Reactant is a foundation for rapid and safe iOS development. It allows you to cut down your development costs by improving reusability, testa

Brightify 374 Nov 22, 2022
Stateful view controller containment for iOS and tvOS

StateViewController When creating rich view controllers, a single view controller class is often tasked with managing the appearance of many other vie

David Ask 309 Nov 29, 2022
YARCH iOS Architecture

YARCH is an architecture pattern developed primarly for iOS applications. You can ask any questions in our telegram channel. Russian version of the re

Alfa Digital 196 Jan 3, 2023
A holistic approach to iOS development, inspired by Redux and MVVM

Tempura is a holistic approach to iOS development, it borrows concepts from Redux (through Katana) and MVVM. ?? Installation Requirements CocoaPods Sw

Bending Spoons 693 Jan 4, 2023
📖 Design Patterns implemented in Swift 5.0

Design Patterns implemented in Swift 5.0 A short cheat-sheet with Xcode 10.2 Playground (Design-Patterns.playground.zip). ???? 中文版 ?? Project started

Oktawian Chojnacki 13.9k Dec 31, 2022
Spin aims to provide a versatile Feedback Loop implementation working with the three main reactive frameworks available in the Swift community (RxSwift, ReactiveSwift and Combine)

With the introduction of Combine and SwiftUI, we will face some transition periods in our code base. Our applications will use both Combine and a thir

Spinners 119 Dec 29, 2022
This is an example of clean architecture and MVVM pattern written in swift

Swift Clean Architecture MVVM This is an example of clean architecture and MVVM pattern written in swift First of all thanks to all of those who made

null 19 Oct 12, 2022
Challenge-viper-finance - Project for VIPER Architecture Dev Sprints on Devpass

VIPER Challenge - Finance App ?? Neste desafio, aplicaremos conceitos da arquite

Devpass 15 Oct 11, 2022
Viper Framework for iOS using Swift

Write an iOS app following VIPER architecture. But in an easy way. Viper the easy way We all know Viper is cool. But we also know that it's hard to se

Ferran Abelló 504 Dec 31, 2022
IOS Swift Application using VIPER Architecture

IOS Swift Application using VIPER Architecture. This is a simple design application for E-Commerce using VIPER architecture and CoreData, I prefer using Delegate Protocols rather than Third Party Library such as Rx but at this project I make it as an example on how to using VIPER.The application also support localization.

Mahmoud Salah 0 Dec 1, 2021