ViperServices
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