ViperServices 1.7.0

ViperServices 1.7.0

Maintained by Siarhei Ladzeika.



  • By
  • Siarhei Ladzeika

ViperServices

Platform CocoaPods Compatible Swift support Build Status

Introduction

ViperServices is dependency injection container for iOS applications written in Swift. It is more lightweight and simple in use than:

Also it introduces 'bootable' concept of service. Also services can define units they depends on.

Changelog

See CHANGELOG

Installation

Cocoapods

This is the recommended way of installing this package.

  • Add the following line to your Podfile
pod 'ViperServices'
  • Run the following command to fetch and build your dependencies
pod install

Manually

If you prefer to install this package manually, just follow these steps:

  • Make sure your project is a git repository. If it isn't, just run this command from your project root folder:
git init
  • Add ViperServices as a git submodule by running the following command.
git submodules add https://github.com/ladeiko/ViperServices.git
  • Add files from 'submodules/ViperServices/Sources' folder to your project.

Usage

  • Define your viper services:
import ViperServices

protocol Service1: AnyObject {
    func foo()
}

class Service1Impl: Service1, ViperService {
    
    func setupDependencies(_ container: ViperServicesContainer) -> [AnyObject]? {
        return [ // depends on
            container.resolve() as Service2
        ]
    }
    
    func boot(launchOptions: [UIApplication.LaunchOptionsKey : Any]?, completion: @escaping ViperServiceBootCompletion) {
        print("boot 1 called")
        completion(.succeeded) // sync completion
    }
    
    func foo() {
        print("foo 1 called")
    }
    
}

protocol Service2: AnyObject {
    func foo()
}

enum Service2Error: Error {
    case SomeError
}

class Service2Impl: Service2, ViperService {
    
    private weak var container: ViperServicesContainer!
    
    func setupDependencies(_ container: ViperServicesContainer) -> [AnyObject]? {
        self.container = container
        return nil
    }
    
    func boot(launchOptions: [UIApplication.LaunchOptionsKey : Any]?, completion: @escaping ViperServiceBootCompletion) {
        print("boot 2 called")
        DispatchQueue.main.asyncAfter(deadline: .now() + 3) { // async completion
            switch arc4random() % 2 { // emulate random result
            case 0:
                completion(.failed(error: Service2Error.SomeError))
            default:
                completion(.succeeded)
            }
            
        }
    }
    
    func foo() {
        print("foo 2 called")
    }
    
}
  • Add following code to application delegate:
var window: UIWindow?

// use DefaultViperServicesContainer or implement your own container
let services = DefaultViperServicesContainer() 

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
    // Override point for customization after application launch.
    
    try! services.register(Service1Impl() as Service1)
    try! services.register(Service2Impl() as Service2)
    
    services.boot(launchOptions: launchOptions) { (result) in
        switch result {
        case .succeeded:
            // All ok, now it is safe to use any service!
            (self.services.resolve() as Service1).foo()
            (self.services.resolve() as Service2).foo()
            
        case let .failed(failedServices):
            // Boot failed, show error to user
            let alert = UIAlertController(title: "Error",
                                      message: failedServices.first!.error.localizedDescription,
                                      preferredStyle: .alert)
            alert.addAction(UIAlertAction(title: "OK", style: .default, handler: nil))
            self.window!.rootViewController?.present(alert, animated: false, completion: nil)
        }
    }
    
    return true
}

LICENSE

This project is licensed under the MIT License - see the LICENSE file for details