- a framework for data management within your mobile app.
- a tool for developers.
- reactive, following the Reactive Extensions (Rx) design patterns.
- lightweight and extensible!
- a replacement for Core Data.
- a replacement for Realm.
- heavyweight.
A detailed description with examples is available on the Motiv Engineering Blog here:
The generic Provider class defines the interface and boilerplate implementation for coordinating access to local and remote data stores. You are responsible for implementing the various domain-specific components, such as converters and storage adapters. The framework handles all the heavy lifting, using your custom components.
The generic ViewModel<T, N> class defines standard behavior common to all view models, including state representation and intent processing. View controllers define observers to respond to user actions by mapping them to intents, which are routed to the view model. All actions taken to change view model state must be encoded as intents.
View components are simple UIKit objects, responsible for representing view state to the user. They also act as a mechanism for users to take action to change view model state by interacting with on-screen components. View delegates, if any, are defined in the controller and must be transformed to view model intents.
The generic Presenter<T, N> class defines the interface and boilerplate implementation for configuring observers and bindings for conveying view model state to the user. Presenter observers subscribe to view model observables to update text, images, view bounds, layout constraints, etc.
pod 'PMVP', '~> 0.7'
Let's say you're creating a class to manage Items.
class ItemProvider: Provider<...> {
Before you define the provider, you need to satisfy its dependencies. You need to create classes for the following:
- ItemProxy: Proxy (the lightweight object you use everywhere in your app to describe an Item)
- ItemLocal: LocalObject (must inherit from LocalObject; typically a Core Data or Realm managed object)
- ItemRemote: RemoteObject (must inherit from RemoteObject; defines the remote object schema)
- ItemLocalConverter: Converter (converts between proxy and local objects)
- ItemRemoteConverter: Converter (converts between proxy and remote objects)
- ItemLocalStorage: LocalStorage (your custom implementation of local data accessors)
- ItemRemoteStorage: RemoteStorage (your custom implementation of lremote data accessors)
Once these are defined, you can create the provider class, as follows:
import PMVP
class ItemProvider: Provider<Int, ItemProxy, ItemLocal, ItemRemote, ItemLocalStorage, ItemRemoteStorage> {
}
itemProvider.objects()
.subscribe(onNext: { items in NSLog("\(items.count) objects") })
.disposed(by: disposeBag)
itemProvider.object(for: 127)
.subscribe(onNext: { item in NSLog(item) })
.disposed(by: disposeBag)
itemProvider.update(item, queue: .main) { result in
switch result {
case .success(let localItem):
NSLog("item updated \(localItem)")
case .failure(let error):
NSLog("failed to update item: \(error)")
}
}
itemProvider.destroy(item, queue: .main) { result in
switch result {
case .success(let localItem):
NSLog("item deleted \(localItem)")
case .failure(let error):
NSLog("failed to delete item: \(error)")
}
}