Skip to content

Commit

Permalink
add DataSources and Presenters
Browse files Browse the repository at this point in the history
  • Loading branch information
marty-suzuki committed Feb 17, 2018
1 parent a6e64b1 commit f298266
Show file tree
Hide file tree
Showing 22 changed files with 776 additions and 410 deletions.
Binary file modified Images/MVC/Views.key
Binary file not shown.
Binary file added Images/MVP/Views.key
Binary file not shown.
Binary file added 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 added 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 added 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 added Images/user_reposiroty.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
46 changes: 40 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,17 +1,51 @@
# iOSDesignPatternSamples (MVC)
# iOSDesignPatternSamples (MVP)

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

## Application Structure

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

## ViewControllers

- [SearchViewController](./iOSDesignPatternSamples/Sources/UI/Search/SearchViewController.swift) -> Search Github user and show user result list
- [FavoriteViewController](./iOSDesignPatternSamples/Sources/UI/Favorite/FavoriteViewController.swift) -> Show local on memory favorite repositories
- [UserRepositoryViewController](./iOSDesignPatternSamples/Sources/UI/UserRepository/UserRepositoryViewController.swift) -> Show Github user's repositories
- [RepositoryViewController](./iOSDesignPatternSamples/Sources/UI/Repository/RepositoryViewController.swift) -> Show a repository and add / remove local on memory favorites
### [SearchViewController](./iOSDesignPatternSamples/Sources/UI/Search/SearchViewController.swift)
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
- [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
- [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)

- [UserRepositoryView](./iOSDesignPatternSamples/Sources/UI/UserRepository/UserRepositoryViewController.swift)
- [UserRepositoryPresenter](./iOSDesignPatternSamples/Sources/UI/UserRepository/UserRepositoryViewPresenter.swift)
- [UserRepositoryViewPresenter](./iOSDesignPatternSamples/Sources/UI/UserRepository/UserRepositoryViewPresenter.swift) <- Adapt UserRepositoryPresenter
- [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

## How to add / remove favorites

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

/* Begin PBXBuildFile section */
37086C1F2017848900D625CA /* NSObjectProtocol.extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37086C1E2017848900D625CA /* NSObjectProtocol.extension.swift */; };
37086C212017850600D625CA /* ApiSession.extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37086C202017850600D625CA /* ApiSession.extension.swift */; };
372936AE1F54538A00762D15 /* FavoriteModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 372936AD1F54538A00762D15 /* FavoriteModel.swift */; };
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 */; };
375C54291F65073900310929 /* SearchViewDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 375C54281F65073900310929 /* SearchViewDataSource.swift */; };
375C542B1F65079A00310929 /* FavoriteViewPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 375C542A1F65079A00310929 /* FavoriteViewPresenter.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 */; };
375C54331F65455700310929 /* UserRepositoryViewDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 375C54321F65455700310929 /* UserRepositoryViewDataSource.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 @@ -30,12 +35,18 @@
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 */; };
/* End PBXBuildFile section */

/* Begin PBXFileReference section */
37086C1E2017848900D625CA /* NSObjectProtocol.extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NSObjectProtocol.extension.swift; sourceTree = "<group>"; };
37086C202017850600D625CA /* ApiSession.extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ApiSession.extension.swift; sourceTree = "<group>"; };
372936AD1F54538A00762D15 /* FavoriteModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FavoriteModel.swift; sourceTree = "<group>"; };
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>"; };
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>"; };
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>"; };
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; };
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>"; };
Expand All @@ -58,6 +69,7 @@
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>"; };
/* End PBXFileReference section */

/* Begin PBXFrameworksBuildPhase section */
Expand All @@ -77,11 +89,11 @@
/* End PBXFrameworksBuildPhase section */

/* Begin PBXGroup section */
37086C1D2017847A00D625CA /* Extension */ = {
37086C2220178F1C00D625CA /* Extension */ = {
isa = PBXGroup;
children = (
37086C202017850600D625CA /* ApiSession.extension.swift */,
37086C1E2017848900D625CA /* NSObjectProtocol.extension.swift */,
37086C2320178F1C00D625CA /* ApiSession.extension.swift */,
37086C2520178F1C00D625CA /* NSObjectProtocol.extension.swift */,
);
path = Extension;
sourceTree = "<group>";
Expand Down Expand Up @@ -135,8 +147,7 @@
isa = PBXGroup;
children = (
37BE2AC11F37460C003DC1F8 /* AppDelegate.swift */,
372936AD1F54538A00762D15 /* FavoriteModel.swift */,
37086C1D2017847A00D625CA /* Extension */,
37086C2220178F1C00D625CA /* Extension */,
37BE2AE91F374889003DC1F8 /* NotieObserver */,
);
path = Common;
Expand All @@ -159,6 +170,8 @@
isa = PBXGroup;
children = (
37BE2AC81F37468C003DC1F8 /* FavoriteViewController.swift */,
375C542A1F65079A00310929 /* FavoriteViewPresenter.swift */,
375C542C1F6509E900310929 /* FavoriteViewDataSource.swift */,
);
path = Favorite;
sourceTree = "<group>";
Expand All @@ -167,6 +180,7 @@
isa = PBXGroup;
children = (
37BE2ACC1F3746E2003DC1F8 /* RepositoryViewController.swift */,
37D5D20A1F6599A900FA46DF /* RepositoryViewPresenter.swift */,
);
path = Repository;
sourceTree = "<group>";
Expand All @@ -175,6 +189,8 @@
isa = PBXGroup;
children = (
37BE2ACA1F374699003DC1F8 /* SearchViewController.swift */,
375C542E1F650EA900310929 /* SearchViewPresenter.swift */,
375C54281F65073900310929 /* SearchViewDataSource.swift */,
);
path = Search;
sourceTree = "<group>";
Expand All @@ -183,6 +199,8 @@
isa = PBXGroup;
children = (
37BE2AD01F3746FA003DC1F8 /* UserRepositoryViewController.swift */,
375C54301F65454000310929 /* UserRepositoryViewPresenter.swift */,
375C54321F65455700310929 /* UserRepositoryViewDataSource.swift */,
37BE2AD11F3746FA003DC1F8 /* UserRepositoryViewController.xib */,
);
path = UserRepository;
Expand Down Expand Up @@ -318,16 +336,22 @@
buildActionMask = 2147483647;
files = (
37BE2AEB1F3748B6003DC1F8 /* UIKeyboardInfo.swift in Sources */,
372936AE1F54538A00762D15 /* FavoriteModel.swift in Sources */,
37086C212017850600D625CA /* ApiSession.extension.swift in Sources */,
375C542B1F65079A00310929 /* FavoriteViewPresenter.swift in Sources */,
375C542F1F650EA900310929 /* SearchViewPresenter.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 */,
37BE2AED1F3748D9003DC1F8 /* UIKeyboardWillHide.swift in Sources */,
37086C1F2017848900D625CA /* NSObjectProtocol.extension.swift in Sources */,
37BE2AC91F37468C003DC1F8 /* FavoriteViewController.swift in Sources */,
37086C2820178F1C00D625CA /* NSObjectProtocol.extension.swift in Sources */,
375C54331F65455700310929 /* UserRepositoryViewDataSource.swift in Sources */,
37BE2AC21F37460C003DC1F8 /* AppDelegate.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
Expand Down
2 changes: 1 addition & 1 deletion iOSDesignPatternSamples/Sources/Common/AppDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
let favoriteVC = viewControllers.flatMap({
($0 as? UINavigationController)?.topViewController as? FavoriteViewController
}).first {
searchVC.favoriteModel = favoriteVC.favoriteModel
searchVC.favoritePresenter = favoriteVC.presenter
}

return true
Expand Down
37 changes: 0 additions & 37 deletions iOSDesignPatternSamples/Sources/Common/FavoriteModel.swift

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -9,61 +9,32 @@
import UIKit
import GithubKit

final class FavoriteViewController: UIViewController {
protocol FavoriteView: class {
func reloadData()
func showRepository(with repository: Repository)
}

final class FavoriteViewController: UIViewController, FavoriteView {
@IBOutlet weak var tableView: UITableView!

let favoriteModel = FavoriteModel()
private(set) lazy var presenter: FavoritePresenter = FavoriteViewPresenter(view: self)
private lazy var dataSource: FavoriteViewDataSource = .init(presenter: self.presenter)

override func viewDidLoad() {
super.viewDidLoad()

title = "On Memory Favorite"
automaticallyAdjustsScrollViewInsets = false

favoriteModel.delegate = self
configure(with: tableView)
}

private func configure(with tableView: UITableView) {
tableView.dataSource = self
tableView.delegate = self

tableView.register(RepositoryViewCell.self)
dataSource.configure(with: tableView)
}

fileprivate func showRepository(with repository: Repository) {
let vc = RepositoryViewController(repository: repository, favoriteModel: favoriteModel)
func showRepository(with repository: Repository) {
let vc = RepositoryViewController(repository: repository, favoritePresenter: presenter)
navigationController?.pushViewController(vc, animated: true)
}
}

extension FavoriteViewController: FavoriteModelDelegate {
func favoriteDidChange() {
tableView.reloadData()
}
}

extension FavoriteViewController: UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return favoriteModel.favorites.count
}

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeue(RepositoryViewCell.self, for: indexPath)
cell.configure(with: favoriteModel.favorites[indexPath.row])
return cell
}
}

extension FavoriteViewController: UITableViewDelegate {
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: false)

let repository = favoriteModel.favorites[indexPath.row]
showRepository(with: repository)
}

func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return RepositoryViewCell.calculateHeight(with: favoriteModel.favorites[indexPath.row], and: tableView)
func reloadData() {
tableView?.reloadData()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
//
// FavoriteViewDataSource.swift
// iOSDesignPatternSamples
//
// Created by marty-suzuki on 2017/09/10.
// Copyright © 2017年 marty-suzuki. All rights reserved.
//

import Foundation
import UIKit
import GithubKit

final class FavoriteViewDataSource: NSObject {
fileprivate let presenter: FavoritePresenter

init(presenter: FavoritePresenter) {
self.presenter = presenter
}

func configure(with tableView: UITableView) {
tableView.dataSource = self
tableView.delegate = self

tableView.register(RepositoryViewCell.self)
}
}

extension FavoriteViewDataSource: UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return presenter.numberOfFavorites
}

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeue(RepositoryViewCell.self, for: indexPath)
let repository = presenter.favoriteRepository(at: indexPath.row)
cell.configure(with: repository)
return cell
}
}

extension FavoriteViewDataSource: UITableViewDelegate {
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: false)
presenter.showFavoriteRepository(at: indexPath.row)
}

func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
let repository = presenter.favoriteRepository(at: indexPath.row)
return RepositoryViewCell.calculateHeight(with: repository, and: tableView)
}
}
Loading

0 comments on commit f298266

Please sign in to comment.