Skip to content

Simple dependency injection container for services written for iOS in swift supporting boot order

License

Notifications You must be signed in to change notification settings

ladeiko/ViperServices

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

34 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

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

About

Simple dependency injection container for services written for iOS in swift supporting boot order

Topics

Resources

License

Stars

Watchers

Forks

Packages

No packages published