Skip to content

Instantly share code, notes, and snippets.


Eric Silverberg esilverberg

View GitHub Profile
View ViewModel state
// 🍎
enum MatchState {
case initial
case error(error: MatchError)
case loading
case started(stack: MatchStack)
case finished(moreStacksAvailable: Bool, canLoadMoreStacks: Bool, newStackAt: Date)
enum Event {
View ViewModel properties
// 🍎
private(set) lazy var matchState =
let mutableMatchState: MutableProperty<MatchState>
private let eventPipe = Signal<Event, Never>.pipe()
var events: Signal<Event, Never> {
return eventPipe.output
View Match logic
// 🍎
final class PSSMatchLogic {
private let accountRepository: PSSAccountRepository
private let matchRepository: PSSMatchRepository
private let locationRepository: PSSLocationRepository
private let featureRepository: PSSFeatureRepository
init(accountRepository: PSSAccountRepository, matchRepository: PSSMatchRepository, locationRepository: PSSLocationRepository, featureRepository: PSSFeatureRepository) {
self.accountRepository = accountRepository
self.matchRepository = matchRepository
View MatchRepository
// 🍎
class PSSMatchRepository {
private let kPrefsHasShownMatchInstructionsKey = "has_shown_match_instructions"
private let api: PSSMatchApiImplementing
private let prefs: PSSPrefsStoreImplementing
init(api: PSSMatchApiImplementing,
prefs: PSSPrefsStoreImplementing) {
self.api = api
View MatchApi
// 🍎
protocol PSSMatchApiImplementing {
func getMatchStack(location: CLLocationCoordinate2D,
browseMode: PSSBrowseMode?,
loadMore: Bool) -> SignalProducer<PSSMatchStack, Error>
func postRate(profile: PSSProfile, rating: PSSProfileRating) -> SignalProducer<Void, Error>
func postRateReminder(profile: PSSProfile) -> SignalProducer<Void, Error>
func deleteRating(profile: PSSProfile) -> SignalProducer<Void, Error>
View View
Type iOS Android
Screens UIViewController Activity, Fragment
Views UIView View
Lists UICollectionView RecyclerView
Data sources UICollectionViewDataSource RecyclerView.Adapter
View ViewModel state change observation
// 🍎
// In our viewDidLoad
viewModel.state.producer.take(duringLifetimeOf: self).startWithValues { [weak self] (state) in
guard let self = self else { return }
switch state {
case .initial: //...
case .error: //...
case .loading: //...
case .started: //...
case .finished: //...
View ViewModel event observation
// 🍎
// in viewDidLoad self).observeValues { [weak self] (event) in
guard let self = self else { return }
switch event {
case .mutualMatch: //...
case .premiumRequired: //...
case .exitMatch: //...
View Registering a repository in a test
// 🍎 Using Swinject
extension Container {
func injectAppRepositories() -> Container {
self.register(PSSMatchRepository.self) { resolver in
return PSSMatchRepository(
api: resolver.resolve(PSSMatchApiImplementing.self)!,
prefs: resolver.resolve(PSSPrefsStoreImplementing.self)!)
View Using DI in tests
// 🍎 Using Quick and Swinject
describe("MatchViewModelTests") {
var container: Container!
var logic: PSSMatchLogic!
var accountRepository: PSSAccountRepository!
var appEventLogger: PSSAppEventLogging!
var viewModel: PSSMatchViewModel!
beforeEach {
container = Container().injectEverythingForTests()