{"id":799,"url":"https://github.com/ferranabello/Viperit","last_synced_at":"2025-08-06T12:31:45.827Z","repository":{"id":41203192,"uuid":"73416937","full_name":"ferranabello/Viperit","owner":"ferranabello","description":"Viper Framework for iOS using Swift","archived":false,"fork":false,"pushed_at":"2021-09-15T10:38:29.000Z","size":7504,"stargazers_count":513,"open_issues_count":3,"forks_count":66,"subscribers_count":22,"default_branch":"master","last_synced_at":"2024-11-30T20:47:27.031Z","etag":null,"topics":["carthage","cocoapods","swift","swift-5","swift5","viper"],"latest_commit_sha":null,"homepage":"","language":"Swift","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ferranabello.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2016-11-10T20:06:02.000Z","updated_at":"2024-11-18T09:57:10.000Z","dependencies_parsed_at":"2022-08-20T22:50:17.806Z","dependency_job_id":null,"html_url":"https://github.com/ferranabello/Viperit","commit_stats":null,"previous_names":[],"tags_count":27,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ferranabello%2FViperit","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ferranabello%2FViperit/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ferranabello%2FViperit/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ferranabello%2FViperit/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ferranabello","download_url":"https://codeload.github.com/ferranabello/Viperit/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":228898277,"owners_count":17988651,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["carthage","cocoapods","swift","swift-5","swift5","viper"],"created_at":"2024-01-05T20:15:31.583Z","updated_at":"2024-12-09T13:30:32.862Z","avatar_url":"https://github.com/ferranabello.png","language":"Swift","funding_links":[],"categories":["Architecture Patterns","Patterns","Uncategorized","Swift","Architecture and State","Patterns [🔝](#readme)","🏗️ Architecture Patterns"],"sub_categories":["Vim","Uncategorized","Other free courses","Getting Started","VIPER"],"readme":"![Viperit](/Assets/logo_light.png)\n\n[![Language](https://img.shields.io/badge/swift-5.1-green.svg)](https://swift.org)\n[![Build Status](https://travis-ci.org/ferranabello/Viperit.svg?branch=master)](https://travis-ci.org/ferranabello/Viperit)\n[![Platform](http://img.shields.io/badge/platform-ios-blue.svg)](https://developer.apple.com/iphone/index.action)\n[![License](http://img.shields.io/badge/license-MIT-orange.svg)](http://mit-license.org)\n[![Codecov](https://img.shields.io/codecov/c/github/ferranabello/Viperit.svg)](https://codecov.io/gh/ferranabello/Viperit)\n[![codebeat badge](https://codebeat.co/badges/17d36823-4e6c-4b45-bad3-746611689636)](https://codebeat.co/projects/github-com-ferranabello-viperit-master)\n[![CocoaPods](https://img.shields.io/cocoapods/v/Viperit.svg)](http://github.com/ferranabello/Viperit)\n[![Carthage Compatible](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat)](https://github.com/Carthage/Carthage)\n[![Accio](https://img.shields.io/badge/Accio-supported-0A7CF5.svg?style=flat)](https://github.com/JamitLabs/Accio)\n[![Swift Package Manager compatible](https://img.shields.io/badge/Swift%20Package%20Manager-compatible-brightgreen.svg)](https://github.com/apple/swift-package-manager)\n[![SwiftUI compatible](https://img.shields.io/badge/SwiftUI-compatible-green.svg)](https://developer.apple.com/xcode/swiftui/)\n\n\nWrite an iOS app following VIPER architecture. But in an **easy way**.\n\n\n## Viper the easy way\nWe 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)](https://www.objc.io/issues/13-architecture/viper/)\n\n## Installation\n\n### Requirements\n\n- iOS 12.0+\n- Swift 5.1+\n- Xcode 12.0+\n\n### Swift Package Manager (SPM)\nYou 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\"\n\n### CocoaPods\n\n[CocoaPods](https://cocoapods.org/) is a dependency manager for Cocoa projects.\n\nSpecify Viperit into your project's Podfile:\n\n```ruby\nsource 'https://github.com/CocoaPods/Specs.git'\nplatform :ios, '12.0'\nuse_frameworks!\n\npod 'Viperit'\n```\n\n### Carthage\n\n[Carthage](https://github.com/Carthage/Carthage) is a decentralized dependency manager that builds your dependencies and provides you with binary frameworks.\n\nTo integrate Viperit into your Xcode project using Carthage, specify it in your `Cartfile`:\n\n```ogdl\ngithub \"ferranabello/Viperit\"\n```\n\nRun `carthage update` to build the framework and drag the built `Viperit.framework` into your Xcode project.\n\n## Features\n\n### Create modules easily using Xcode templates\nViperit Xcode templates can be downloaded from the [latest release](https://github.com/ferranabello/Viperit/releases) page. Download the **Templates.zip** file.\n\nTo install them, unzip the file, open your terminal and run:\n\n```bash\ncd PATH/TO/UNZIPPED/FOLDER\nmkdir -p ~/Library/Developer/Xcode/Templates/\ncp -R Viperit ~/Library/Developer/Xcode/Templates/\n```\n\n![Module Creation](/Assets/Instructions/module_creation.gif)\n\nYou can check \"Also create a Storyboard file for module\" if you want the storyboard file to be automatically created for you.\nChoose 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.\n\n### Use storyboard, xib, programmatic views or SwiftUI\nAny 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:\n\n```swift\nenum MySuperCoolModules: String, ViperitModule {\n    case theStoryboardThing  \n    case oldSchool\n    case xibModule\n    case whatTheSwift\n\n    var viewType: ViperitViewType {\n        switch self {\n        case .theStoryboardThing: return .storyboard\n        case .oldSchool: return .code\n        case .xibModule: return .nib\n        case .whatTheSwift: return .swiftUI\n        }\n    }\n}\n```\n\n### Built-in router functions\nThis 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:\n```swift\n    //Show your module as the root view controller of the given window\n    func show(inWindow window: UIWindow?, embedInNavController: Bool, setupData: Any?, makeKeyAndVisible: Bool)\n\n    //Show your module from any given view controller\n    func show(from: UIViewController, embedInNavController: Bool, setupData: Any?)\n\n    //Show your module inside another view\n    func show(from containerView: UIViewController, insideView targetView: UIView, setupData: Any?)\n\n    //Present your module modally\n    func present(from: UIViewController, embedInNavController: Bool, presentationStyle: UIModalPresentationStyle, transitionStyle: UIModalTransitionStyle, setupData: Any?, completion: (() -\u003e Void)?)\n```\n\n### Easy to test\nYou can test your module injecting mock layers like so:\n```swift\n    var module = AppModules.home.build()\n    view = HomeMockView()\n    view.expectation = expectation(description: \"Test expectation\")\n    module.injectMock(view: view)\n    ...\n```\n\n## Usage\nNow, let's create our first Viperit module called \"myFirstModule\"!\n\n### 0. Create your module files\nLet's use the provided Xcode template to easily create all the needed classes for the module. Just click \u003ci class=\"icon-file\"\u003e\u003c/i\u003e **New file** in the document panel and choose between **Protocol-oriented module**,  **Object-oriented module** or **SwiftUI module** under the \"Viperit\" section.\n\n### 1. Create a modules enum\nYou 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.\n```swift\nimport Viperit\n\n//MARK: - Application modules\nenum AppModules: String, ViperitModule {\n    case myFirstModule\n}\n```\n\n### 2. Build the module and perform navigation\nImagine this is a new app and we want to load our \"myFirstModule\" module as the app's startup module\n```swift\nimport Viperit\n\n@UIApplicationMain\nclass AppDelegate: UIResponder, UIApplicationDelegate {\n    var window: UIWindow?\n\n    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -\u003e Bool {\n        window = UIWindow(frame: UIScreen.main.bounds)\n        let module = AppModules.myFirstModule.build()\n        let router = module.router as! MyFirstModuleRouter\n        router.show(inWindow: window)\n        return true\n    }\n}\n```\nThis is just an example, you could of course use your own router functions instead of the provided show(inWindow:):\n```swift\n    window = UIWindow(frame: UIScreen.main.bounds)\n    let module = AppModules.myFirstModule.build()\n    let router = module.router as! MyFirstModuleRouter\n    router.mySuperCoolShowFunction(inWindow: window)\n```\n\n### 2.1. Are you using SwiftUI?\nLet's say you created a module based on SwiftUI called 'Cool'.\nAll you need to do is to use the new Viperit SwiftUI module builder:\n\n```swift\nimport SwiftUI\nimport Viperit\n\n//A sample function that could be implemented in some Router to show your Cool SwiftUI module\n//You can even inject an @EnvironmentObject view model to your SwiftUI view.\nfunc showTheCoolModule() {\n  let module = AppModules.cool.build { presenter -\u003e (CoolView, UserSettings) in\n      let p = presenter as! CoolPresenterApi\n      let settings = p.settings()\n      return (CoolView(presenter: p), settings)\n  }\n  let router = module.router as! CoolRouter\n  router.show(from: viewController)\n}\n```\n\nCheck the example app to have a better understanding of how it works, and how to manage data flow on SwiftUI with the presenter.\n\n### 3. Follow the Viper flow\nEverything is ready for you to make great things the Viper way!\nClone the repo and run the 'Example' target to see it in action! Or just try it with Cocoapods:\n```ruby\npod try Viperit\n```\n\n## Author\n\n[Ferran Abelló](https://www.github.com/ferranabello \"Ferran Abelló Github\")\n\n## License\n\nViperit is released under [MIT license](https://raw.githubusercontent.com/ferranabello/viperit/master/LICENSE) and copyrighted by Ferran Abelló.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fferranabello%2FViperit","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fferranabello%2FViperit","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fferranabello%2FViperit/lists"}