PMVP is...
- a framework for data management within your mobile app.
- a tool for developers.
- reactive, following the Reactive Extensions (Rx) design patterns.
- lightweight and extensible!
PMVP is not...
- a replacement for Core Data.
- a replacement for Realm.
- heavyweight.
Overview
A detailed description with examples is available on the Motiv Engineering Blog here:
Provider
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.
Model
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
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.
Presenter
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.
Getting Started
Podfile
pod 'PMVP', '~> 0.4'
Implement required components
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> {
}
Usage
Observing the collection
itemProvider.objects()
.subscribe(onNext: { items in NSLog("\(items.count) objects") })
.disposed(by: disposeBag)
Observing one item
itemProvider.object(for: 127)
.subscribe(onNext: { item in NSLog(item) })
.disposed(by: disposeBag)
Creating/Updating items
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)")
}
}
Destroying an item
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)")
}
}