[アーキテクチャ]Clean SWIFT(VIP)
本当にきれいではありませんか?
ViewController Interactor Presenter Worker Router Models Clean Architectureに基づいてIOSを再解釈した結果をClean SWIFTと呼ぶ.
ViewController、Interactor、Presenterの最初のアルファベットによってVIPモードとも呼ばれます.
公式サイトの画像で.
最大の特徴は、元のデータストリームを生成することです.
ViewController
画面表示とユーザーインタラクションを担当
Interactor
業務ロジックを担当する
Presenter
Interactorから得られた結果をビューの表示可能な形式に変換する責任を負う
Worker
Interactorから複雑な論理を分離または拡張するために使用
Router
スクリーン移動を担当するロジック
Models
UseCaseとケース階層型データ構造の定義
詳細についてはここをご確認ください.
CLEAN SWIFTは、ファイルの分離によって役割や注目点を分離したいと考えています.
この点は規模の小さい開発を行うと効率が低下する.
しかし,ファイルに分離されるため,各階層の機能は明確に区別できる.
イベントが発生すると、そのビジネスロジックを実装する関数が呼び出されます.
ビジネスロジックを担当し、詳細はWorkerが処理します.
Interactorから受信したデータをビューに変換して転送します.
インタラクティブで必要な詳細なビジネスロジックを実装します.
Segueにより画面移動やコード化が可能です.
SwinjectのようなDIを使用すれば、ViewControllerのsetupを分離することができる.
またpassData関数でScene間でデータを渡すこともできます.
Sceneで使用するUserCaseを定義し、ケースの階層型データ構造を定義します.
完全なコードは羽状バニラにあります.
Clean Swift?
ViewController、Interactor、Presenterの最初のアルファベットによってVIPモードとも呼ばれます.
公式サイトの画像で.
最大の特徴は、元のデータストリームを生成することです.
ViewController
画面表示とユーザーインタラクションを担当
Interactor
業務ロジックを担当する
Presenter
Interactorから得られた結果をビューの表示可能な形式に変換する責任を負う
Worker
Interactorから複雑な論理を分離または拡張するために使用
Router
スクリーン移動を担当するロジック
Models
UseCaseとケース階層型データ構造の定義
詳細についてはここをご確認ください.
インプリメンテーション
CLEAN SWIFTは、ファイルの分離によって役割や注目点を分離したいと考えています.
この点は規模の小さい開発を行うと効率が低下する.
しかし,ファイルに分離されるため,各階層の機能は明確に区別できる.
ViewController
イベントが発生すると、そのビジネスロジックを実装する関数が呼び出されます.
func searchBarSearchButtonClicked(_ searchBar: UISearchBar) {
interactor?.fetchRepositories(request: Search.FetchRepositories.Request(text: searchBar.text))
}
リストを更新するための関数を実装します.func displayRepositories(viewModel: Search.FetchRepositories.ViewModel) {
DispatchQueue.main.async {
self.displayedRepositories = viewModel.fetchedRepositories
self.tableView.reloadData()
}
}
Interactor
ビジネスロジックを担当し、詳細はWorkerが処理します.
func fetchRepositories(request: Search.FetchRepositories.Request) {
worker = SearchWorker()
worker?.fetchRepositories(text: request.text, completion: { result in
switch result {
case .success(let response):
self.repositories = response.items
self.presenter?.presentFetchedRepositories(response: response)
case .failure(let error):
print("error : \(error.localizedDescription)")
let response = Search.FetchRepositories.Response()
self.repositories = response.items
self.presenter?.presentFetchedRepositories(response: response)
}
})
}
Presenter
Interactorから受信したデータをビューに変換して転送します.
func presentFetchedRepositories(response: Search.FetchRepositories.Response) {
let viewModel = Search.FetchRepositories.ViewModel(fetchedRepositories: response.items)
self.viewController?.displayRepositories(viewModel: viewModel)
}
Worker
インタラクティブで必要な詳細なビジネスロジックを実装します.
func fetchRepositories(text: String?, completion: @escaping(Result<Search.FetchRepositories.Response, Error>) -> Void) {
var urlComponents = URLComponents(string: "https://api.github.com/search/repositories")
urlComponents?.queryItems = [
URLQueryItem(name: "q", value: text)
]
URLSession.shared.dataTask(with: (urlComponents?.url)!) { data, response, error in
guard error == nil else {
completion(.failure(error!))
return
}
if let response = response as? HTTPURLResponse, response.statusCode == 200, let data = data {
do {
let searchResponse = try JSONDecoder().decode(Search.FetchRepositories.Response.self, from: data)
completion(.success(searchResponse))
} catch {
print("error : \(error.localizedDescription)")
completion(.failure(error))
}
}
}.resume()
}
Router
Segueにより画面移動やコード化が可能です.
SwinjectのようなDIを使用すれば、ViewControllerのsetupを分離することができる.
またpassData関数でScene間でデータを渡すこともできます.
func routeToSearchDetail(segue: UIStoryboardSegue?) {
if let segue = segue {
let destinationVC = segue.destination as! SearchDetailViewController
var destinationDS = destinationVC.router!.dataStore!
passDataToSearchDetail(source: dataStore!, destination: &destinationDS)
} else {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let destinationVC = storyboard.instantiateViewController(withIdentifier: "SearchDetailViewController") as! SearchDetailViewController
var destinationDS = destinationVC.router!.dataStore!
passDataToSearchDetail(source: dataStore!, destination: &destinationDS)
navigateToSearchDetail(source: viewController!, destination: destinationVC)
}
}
Models
Sceneで使用するUserCaseを定義し、ケースの階層型データ構造を定義します.
enum Search {
// MARK: Use cases
enum FetchRepositories {
struct Request {
let text: String?
}
struct Response: Codable {
var total_count: Int = 0
var incomplete_results: Bool = false
var items: [Repository] = []
}
struct ViewModel {
let fetchedRepositories: [Repository]
}
}
}
結果
完全なコードは羽状バニラにあります.
Reference
この問題について([アーキテクチャ]Clean SWIFT(VIP)), 我々は、より多くの情報をここで見つけました https://velog.io/@hanchi0/아키텍처-Clean-SwiftVIPテキストは自由に共有またはコピーできます。ただし、このドキュメントのURLは参考URLとして残しておいてください。
Collection and Share based on the CC Protocol