Skip to content

Commit

Permalink
add viewModels
Browse files Browse the repository at this point in the history
  • Loading branch information
marty-suzuki committed Feb 17, 2018
1 parent f298266 commit e16f4d2
Show file tree
Hide file tree
Showing 26 changed files with 760 additions and 616 deletions.
Binary file added Images/MVVM/Views.key
Binary file not shown.
Binary file modified Images/favorite.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified Images/repository.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified Images/search.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified Images/structure.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file removed Images/user_reposiroty.png
Binary file not shown.
Binary file added Images/user_repository.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
22 changes: 7 additions & 15 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# iOSDesignPatternSamples (MVP)
# iOSDesignPatternSamples (MVVM)

This is Github user search demo app that made with MVP design pattern.
This is Github user search demo app that made with MVVM design pattern.

## Application Structure

Expand All @@ -13,39 +13,31 @@ Search Github user and show user result list

![](./Images/search.png)

- [SearchView](./iOSDesignPatternSamples/Sources/UI/Search/SearchViewController.swift)
- [SearchPresenter](./iOSDesignPatternSamples/Sources/UI/Search/SearchViewPresenter.swift)
- [SearchViewPresenter](./iOSDesignPatternSamples/Sources/UI/Search/SearchViewPresenter.swift) <- Adapt SearchPresenter
- [SearchViewModel](./iOSDesignPatternSamples/Sources/UI/Search/SearchViewModel.swift)
- [SearchViewDataSource](./iOSDesignPatternSamples/Sources/UI/Search/SearchViewDataSource.swift) <- Adapt UITableViewDataSource and UITableViewDelegate

### [FavoriteViewController](./iOSDesignPatternSamples/Sources/UI/Favorite/FavoriteViewController.swift)
Show local on memory favorite repositories

![](./Images/favorite.png)

- [FavoriteView](./iOSDesignPatternSamples/Sources/UI/Favorite/FavoriteViewController.swift)
- [FavoritePresenter](./iOSDesignPatternSamples/Sources/UI/Favorite/FavoriteViewPresenter.swift)
- [FavoriteViewPresenter](./iOSDesignPatternSamples/Sources/UI/Favorite/FavoriteViewPresenter.swift) <- Adapt FavoritePresenter
- [FavoriteViewModel](./iOSDesignPatternSamples/Sources/UI/Favorite/FavoriteViewModel.swift)
- [FavoriteViewDataSource](./iOSDesignPatternSamples/Sources/UI/Favorite/FavoriteViewDataSource.swift) <- Adapt UITableViewDataSource and UITableViewDelegate

### [UserRepositoryViewController](./iOSDesignPatternSamples/Sources/UI/UserRepository/UserRepositoryViewController.swift)
Show Github user's repositories

![](./Images/user_reposiroty.png)
![](./Images/user_repository.png)

- [UserRepositoryView](./iOSDesignPatternSamples/Sources/UI/UserRepository/UserRepositoryViewController.swift)
- [UserRepositoryPresenter](./iOSDesignPatternSamples/Sources/UI/UserRepository/UserRepositoryViewPresenter.swift)
- [UserRepositoryViewPresenter](./iOSDesignPatternSamples/Sources/UI/UserRepository/UserRepositoryViewPresenter.swift) <- Adapt UserRepositoryPresenter
- [UserRepositoryViewModel](./iOSDesignPatternSamples/Sources/UI/UserRepository/UserRepositoryViewModel.swift)
- [UserRepositoryViewDataSource](./iOSDesignPatternSamples/Sources/UI/UserRepository/UserRepositoryViewDataSource.swift) <- Adapt UITableViewDataSource and UITableViewDelegate

### [RepositoryViewController](./iOSDesignPatternSamples/Sources/UI/Repository/RepositoryViewController.swift)
Show a repository and add / remove local on memory favorites

![](./Images/repository.png)

- [RepositoryView](./iOSDesignPatternSamples/Sources/UI/Repository/RepositoryViewController.swift)
- [RepositoryPresenter](./iOSDesignPatternSamples/Sources/UI/Repository/RepositoryViewPresenter.swift)
- [RepositoryViewPresenter](./iOSDesignPatternSamples/Sources/UI/Repository/RepositoryViewPresenter.swift) <- Adapt RepositoryPresenter
- [RepositoryViewModel](./iOSDesignPatternSamples/Sources/UI/Repository/RepositoryViewModel.swift)

## How to add / remove favorites

Expand Down
61 changes: 35 additions & 26 deletions iOSDesignPatternSamples.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,15 @@
objects = {

/* Begin PBXBuildFile section */
37086C2620178F1C00D625CA /* ApiSession.extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37086C2320178F1C00D625CA /* ApiSession.extension.swift */; };
37086C2820178F1C00D625CA /* NSObjectProtocol.extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37086C2520178F1C00D625CA /* NSObjectProtocol.extension.swift */; };
37086C2D2017941900D625CA /* ApiSession.extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37086C2A2017941900D625CA /* ApiSession.extension.swift */; };
37086C2F2017941900D625CA /* NSObjectProtocol.extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37086C2C2017941900D625CA /* NSObjectProtocol.extension.swift */; };
375C54291F65073900310929 /* SearchViewDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 375C54281F65073900310929 /* SearchViewDataSource.swift */; };
375C542B1F65079A00310929 /* FavoriteViewPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 375C542A1F65079A00310929 /* FavoriteViewPresenter.swift */; };
375C542B1F65079A00310929 /* FavoriteViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 375C542A1F65079A00310929 /* FavoriteViewModel.swift */; };
375C542D1F6509E900310929 /* FavoriteViewDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 375C542C1F6509E900310929 /* FavoriteViewDataSource.swift */; };
375C542F1F650EA900310929 /* SearchViewPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 375C542E1F650EA900310929 /* SearchViewPresenter.swift */; };
375C54311F65454000310929 /* UserRepositoryViewPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 375C54301F65454000310929 /* UserRepositoryViewPresenter.swift */; };
375C542F1F650EA900310929 /* SearchViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 375C542E1F650EA900310929 /* SearchViewModel.swift */; };
375C54311F65454000310929 /* UserRepositoryViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 375C54301F65454000310929 /* UserRepositoryViewModel.swift */; };
375C54331F65455700310929 /* UserRepositoryViewDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 375C54321F65455700310929 /* UserRepositoryViewDataSource.swift */; };
37B1108E2017A8B90047B21D /* Value.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37B1108D2017A8B90047B21D /* Value.swift */; };
37BE2ABB1F3745D0003DC1F8 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 37BE2AB31F3745D0003DC1F8 /* Assets.xcassets */; };
37BE2ABC1F3745D0003DC1F8 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 37BE2AB41F3745D0003DC1F8 /* LaunchScreen.storyboard */; };
37BE2ABD1F3745D0003DC1F8 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 37BE2AB61F3745D0003DC1F8 /* Main.storyboard */; };
Expand All @@ -35,19 +36,21 @@
37BE2AEF1F3748EF003DC1F8 /* UIKeyboardWillShow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37BE2AEE1F3748EF003DC1F8 /* UIKeyboardWillShow.swift */; };
37BE2AF51F3759E7003DC1F8 /* LoadingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37BE2AF41F3759E7003DC1F8 /* LoadingView.swift */; };
37BE2AF71F3759F0003DC1F8 /* LoadingView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 37BE2AF61F3759F0003DC1F8 /* LoadingView.xib */; };
37D5D20B1F6599A900FA46DF /* RepositoryViewPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37D5D20A1F6599A900FA46DF /* RepositoryViewPresenter.swift */; };
37D5D20B1F6599A900FA46DF /* RepositoryViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37D5D20A1F6599A900FA46DF /* RepositoryViewModel.swift */; };
9DDAB3C11F66328B00D2EE00 /* RxCocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9DDAB3C01F66328A00D2EE00 /* RxCocoa.framework */; };
/* End PBXBuildFile section */

/* Begin PBXFileReference section */
37086C2320178F1C00D625CA /* ApiSession.extension.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ApiSession.extension.swift; sourceTree = "<group>"; };
37086C2520178F1C00D625CA /* NSObjectProtocol.extension.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NSObjectProtocol.extension.swift; sourceTree = "<group>"; };
37086C2A2017941900D625CA /* ApiSession.extension.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ApiSession.extension.swift; sourceTree = "<group>"; };
37086C2C2017941900D625CA /* NSObjectProtocol.extension.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NSObjectProtocol.extension.swift; sourceTree = "<group>"; };
375C54281F65073900310929 /* SearchViewDataSource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchViewDataSource.swift; sourceTree = "<group>"; };
375C542A1F65079A00310929 /* FavoriteViewPresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FavoriteViewPresenter.swift; sourceTree = "<group>"; };
375C542A1F65079A00310929 /* FavoriteViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FavoriteViewModel.swift; sourceTree = "<group>"; };
375C542C1F6509E900310929 /* FavoriteViewDataSource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FavoriteViewDataSource.swift; sourceTree = "<group>"; };
375C542E1F650EA900310929 /* SearchViewPresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchViewPresenter.swift; sourceTree = "<group>"; };
375C54301F65454000310929 /* UserRepositoryViewPresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserRepositoryViewPresenter.swift; sourceTree = "<group>"; };
375C542E1F650EA900310929 /* SearchViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchViewModel.swift; sourceTree = "<group>"; };
375C54301F65454000310929 /* UserRepositoryViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserRepositoryViewModel.swift; sourceTree = "<group>"; };
375C54321F65455700310929 /* UserRepositoryViewDataSource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserRepositoryViewDataSource.swift; sourceTree = "<group>"; };
37817D031F373F8B00EC69C6 /* iOSDesignPatternSamples.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = iOSDesignPatternSamples.app; sourceTree = BUILT_PRODUCTS_DIR; };
37B1108D2017A8B90047B21D /* Value.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Value.swift; sourceTree = "<group>"; };
37BE2AB31F3745D0003DC1F8 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
37BE2AB51F3745D0003DC1F8 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
37BE2AB71F3745D0003DC1F8 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
Expand All @@ -69,14 +72,16 @@
37BE2AEE1F3748EF003DC1F8 /* UIKeyboardWillShow.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UIKeyboardWillShow.swift; sourceTree = "<group>"; };
37BE2AF41F3759E7003DC1F8 /* LoadingView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LoadingView.swift; sourceTree = "<group>"; };
37BE2AF61F3759F0003DC1F8 /* LoadingView.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = LoadingView.xib; sourceTree = "<group>"; };
37D5D20A1F6599A900FA46DF /* RepositoryViewPresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RepositoryViewPresenter.swift; sourceTree = "<group>"; };
37D5D20A1F6599A900FA46DF /* RepositoryViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RepositoryViewModel.swift; sourceTree = "<group>"; };
9DDAB3C01F66328A00D2EE00 /* RxCocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = RxCocoa.framework; path = Carthage/Build/iOS/RxCocoa.framework; sourceTree = "<group>"; };
/* End PBXFileReference section */

/* Begin PBXFrameworksBuildPhase section */
37817D001F373F8B00EC69C6 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
9DDAB3C11F66328B00D2EE00 /* RxCocoa.framework in Frameworks */,
37BE2AE81F37480F003DC1F8 /* NoticeObserveKit.framework in Frameworks */,
37BE2AE31F374790003DC1F8 /* GithubKit.framework in Frameworks */,
37BE2AE41F374790003DC1F8 /* Nuke.framework in Frameworks */,
Expand All @@ -89,11 +94,12 @@
/* End PBXFrameworksBuildPhase section */

/* Begin PBXGroup section */
37086C2220178F1C00D625CA /* Extension */ = {
37086C292017941900D625CA /* Extension */ = {
isa = PBXGroup;
children = (
37086C2320178F1C00D625CA /* ApiSession.extension.swift */,
37086C2520178F1C00D625CA /* NSObjectProtocol.extension.swift */,
37086C2A2017941900D625CA /* ApiSession.extension.swift */,
37086C2C2017941900D625CA /* NSObjectProtocol.extension.swift */,
37B1108D2017A8B90047B21D /* Value.swift */,
);
path = Extension;
sourceTree = "<group>";
Expand Down Expand Up @@ -147,7 +153,7 @@
isa = PBXGroup;
children = (
37BE2AC11F37460C003DC1F8 /* AppDelegate.swift */,
37086C2220178F1C00D625CA /* Extension */,
37086C292017941900D625CA /* Extension */,
37BE2AE91F374889003DC1F8 /* NotieObserver */,
);
path = Common;
Expand All @@ -170,7 +176,7 @@
isa = PBXGroup;
children = (
37BE2AC81F37468C003DC1F8 /* FavoriteViewController.swift */,
375C542A1F65079A00310929 /* FavoriteViewPresenter.swift */,
375C542A1F65079A00310929 /* FavoriteViewModel.swift */,
375C542C1F6509E900310929 /* FavoriteViewDataSource.swift */,
);
path = Favorite;
Expand All @@ -180,7 +186,7 @@
isa = PBXGroup;
children = (
37BE2ACC1F3746E2003DC1F8 /* RepositoryViewController.swift */,
37D5D20A1F6599A900FA46DF /* RepositoryViewPresenter.swift */,
37D5D20A1F6599A900FA46DF /* RepositoryViewModel.swift */,
);
path = Repository;
sourceTree = "<group>";
Expand All @@ -189,7 +195,7 @@
isa = PBXGroup;
children = (
37BE2ACA1F374699003DC1F8 /* SearchViewController.swift */,
375C542E1F650EA900310929 /* SearchViewPresenter.swift */,
375C542E1F650EA900310929 /* SearchViewModel.swift */,
375C54281F65073900310929 /* SearchViewDataSource.swift */,
);
path = Search;
Expand All @@ -199,7 +205,7 @@
isa = PBXGroup;
children = (
37BE2AD01F3746FA003DC1F8 /* UserRepositoryViewController.swift */,
375C54301F65454000310929 /* UserRepositoryViewPresenter.swift */,
375C54301F65454000310929 /* UserRepositoryViewModel.swift */,
375C54321F65455700310929 /* UserRepositoryViewDataSource.swift */,
37BE2AD11F3746FA003DC1F8 /* UserRepositoryViewController.xib */,
);
Expand All @@ -209,6 +215,7 @@
37BE2AD41F37471B003DC1F8 /* Frameworks */ = {
isa = PBXGroup;
children = (
9DDAB3C01F66328A00D2EE00 /* RxCocoa.framework */,
37BE2AE71F37480F003DC1F8 /* NoticeObserveKit.framework */,
37BE2ADF1F374790003DC1F8 /* GithubKit.framework */,
37BE2AE01F374790003DC1F8 /* Nuke.framework */,
Expand Down Expand Up @@ -321,6 +328,7 @@
"$(SRCROOT)/Carthage/Build/iOS/SwiftIconFont.framework",
"$(SRCROOT)/Carthage/Build/iOS/GithubKit.framework",
"$(SRCROOT)/Carthage/Build/iOS/NoticeObserveKit.framework",
"$(SRCROOT)/Carthage/Build/iOS/RxCocoa.framework",
);
outputPaths = (
);
Expand All @@ -336,21 +344,22 @@
buildActionMask = 2147483647;
files = (
37BE2AEB1F3748B6003DC1F8 /* UIKeyboardInfo.swift in Sources */,
375C542B1F65079A00310929 /* FavoriteViewPresenter.swift in Sources */,
375C542F1F650EA900310929 /* SearchViewPresenter.swift in Sources */,
375C542B1F65079A00310929 /* FavoriteViewModel.swift in Sources */,
375C542F1F650EA900310929 /* SearchViewModel.swift in Sources */,
37BE2ACE1F3746E2003DC1F8 /* RepositoryViewController.swift in Sources */,
37BE2AF51F3759E7003DC1F8 /* LoadingView.swift in Sources */,
375C542D1F6509E900310929 /* FavoriteViewDataSource.swift in Sources */,
37BE2ACB1F374699003DC1F8 /* SearchViewController.swift in Sources */,
375C54291F65073900310929 /* SearchViewDataSource.swift in Sources */,
37BE2AEF1F3748EF003DC1F8 /* UIKeyboardWillShow.swift in Sources */,
37BE2AD21F3746FA003DC1F8 /* UserRepositoryViewController.swift in Sources */,
37086C2620178F1C00D625CA /* ApiSession.extension.swift in Sources */,
375C54311F65454000310929 /* UserRepositoryViewPresenter.swift in Sources */,
37D5D20B1F6599A900FA46DF /* RepositoryViewPresenter.swift in Sources */,
37086C2D2017941900D625CA /* ApiSession.extension.swift in Sources */,
375C54311F65454000310929 /* UserRepositoryViewModel.swift in Sources */,
37D5D20B1F6599A900FA46DF /* RepositoryViewModel.swift in Sources */,
37BE2AED1F3748D9003DC1F8 /* UIKeyboardWillHide.swift in Sources */,
37BE2AC91F37468C003DC1F8 /* FavoriteViewController.swift in Sources */,
37086C2820178F1C00D625CA /* NSObjectProtocol.extension.swift in Sources */,
37B1108E2017A8B90047B21D /* Value.swift in Sources */,
37086C2F2017941900D625CA /* NSObjectProtocol.extension.swift in Sources */,
375C54331F65455700310929 /* UserRepositoryViewDataSource.swift in Sources */,
37BE2AC21F37460C003DC1F8 /* AppDelegate.swift in Sources */,
);
Expand Down
3 changes: 2 additions & 1 deletion iOSDesignPatternSamples/Sources/Common/AppDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
let favoriteVC = viewControllers.flatMap({
($0 as? UINavigationController)?.topViewController as? FavoriteViewController
}).first {
searchVC.favoritePresenter = favoriteVC.presenter
searchVC.favoritesInput = favoriteVC.favoritesInput
searchVC.favoritesOutput = favoriteVC.favoritesOutput
}

return true
Expand Down
23 changes: 23 additions & 0 deletions iOSDesignPatternSamples/Sources/Common/Extension/Value.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
//
// Value.swift
// iOSDesignPatternSamples
//
// Created by marty-suzuki on 2018/01/24.
// Copyright © 2018年 marty-suzuki. All rights reserved.
//

import Foundation

struct Value<Base> {
let base: Base
}

protocol ValueCompatible {
var value: Value<Self> { get }
}

extension ValueCompatible {
var value: Value<Self> {
return Value(base: self)
}
}
Loading

0 comments on commit e16f4d2

Please sign in to comment.