Router dan Data Passing Clean Swift Architecture

Halo pembaca!

Dalam artikel sebelumnya , saya berbicara tentang siklus VIP arsitektur Clean Swift . Sekarang kita akan menyentuh salah satu topik paling penting - transisi dan transfer data antar adegan.



Teori


Komponen Router bertanggung jawab atas navigasi dan transfer data, yang merupakan bagian dari adegan (opsional tentu saja). Ini diinisialisasi dalam ViewController , bersama dengan Interactor dan Presenter .

Router mengimplementasikan dua protokol - RoutingLogic dan DataPassing , yang akan kami isi dengan fungsionalitas kami. RoutingLogic harus berisi metode yang bertanggung jawab untuk transisi ke adegan tertentu. DataPassing berisi variabel dataStore , yang merujuk pada Protokol DataStore . Adegan Interactor mengimplementasikan protokol DataStore dan bekerja dengan variabel yang disimpan di dalamnya. Router itu sendiri berisi tautan ke ViewController dari adegannya.

Menggunakan tautan ke ViewController , Router melompat di antara layar. Untuk melakukan ini, Anda dapat menggunakan Segue atau membuat adegan yang ingin Anda transisikan, secara terprogram. Metode mana yang digunakan tidak penting, hal utama bagi kita adalah memiliki tautan ke turunan kelas ViewController yang akan kita gunakan.

Dengan menggunakan tautan ke DataStore, kami akan mentransfer data dari Interactor dari satu adegan ke Interactor dari adegan yang kami pindahkan. Dan, seperti yang disebutkan sebelumnya, Routerlah yang perlu tahu bagaimana melakukan ini.

Berlatih


Sebagai contoh, kami akan mentransfer teks dari TextField ke Label adegan lain. Mari kita pertimbangkan dua cara transisi antar adegan - menurut Segue dan secara terprogram.

Kelas Router berisi 3 kelompok metode semantik:

  1. Metode dari implementasi RoutingLogic (routeTo)
  2. Metode yang bertanggung jawab untuk navigasi (navigasikan ke, transisi tanpa Segue)
  3. Metode untuk transfer data (passDataTo, jika ada data untuk transfer)



Jika kita melakukan transisi melalui Segue , misalnya, ketika sebuah tombol diklik, maka di ViewController kita harus mengganti metode prep (for: sender :). Ekstensi ini akan memungkinkan Anda untuk secara otomatis memanggil metode dari Router dengan nama Segue .

Mempersiapkan persiapan (untuk: pengirim :) adalah opsional ketika bekerja dengan Segue. Anda dapat mengecualikannya dari kode dan memanggil performSegue (withIdentifier: sender :) dalam metode Router . Mempersiapkan hanya diperlukan jika Anda perlu menggunakan Segue bersama dengan transfer data.

final class HomeViewController: UIViewController {
// ...
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
// Segue
if let scene = segue.identifier {
// , Router
// router?.routeToNAME(segue:)
let selector = NSSelectorFromString("routeTo\(scene)WithSegue:")
// ,
// Segue
if let router = router, router.responds(to: selector) {
router.perform(selector, with: segue)
}
}
}
// ...
}


Sekarang akhirnya kita sampai pada hal yang paling menarik - kode Router . Contoh tersebut berisi komentar, jadi kami hanya akan mempertimbangkan poin-poin penting.

Di Router ini , kami bekerja dengan dua adegan - Beranda dan Detail . Transisi dari adegan Home juga ditangani dalam dua cara - oleh Segue dan secara terprogram . Data ditransfer dari adegan Beranda ke adegan Detail .

Semua metode dalam protokol RoutingLogic harus dinamai sesuai dengan prinsip routeToNAME , di mana NAME adalah nama Segue (Identifier) โ€‹โ€‹yang kami tentukan saat bekerja dengan Storyboard . Ini diperlukan tidak hanya untuk kenyamanan dan keindahan penggunaan, tetapi juga untuk pemilih metode kami dalam persiapan (untuk: pengirim :) ViewController , yang telah kami definisikan ulang sebelumnya.

Juga di kelas HomeRouter ada metode yang dimulai dengan navigTo dan passDataTo . Yang pertama bertanggung jawab untuk logika transisi, sedangkan yang kedua bertanggung jawab untuk transfer data. Metode navigo hanya dibuat jika transisi dilakukan secara terprogram.

Pada contoh, kita memiliki metode routeToDetail (segue :) . Parameter segue bersifat opsional sejak itu metode ini berisi implementasi yang memungkinkan Anda untuk memanggilnya tanpa menggunakan Segue . Dalam kedua kasus transisi, kita mendapatkan nilai-nilai non-opsional dari adegan HomeViewController'a dan HomeDataStore'a kami, serta tautan ke adegan ViewController dan DataStore Detail . Di sini perlu diperhatikan fakta bahwa detailDS adalah variabel dan diteruskan ke metode passDataToDetail menggunakan parameter pass -through (inout). Ini penting karena tanpa inout, kita harus menandai semua protokol DataStore sebagai "mungkin untuk diimplementasikan hanya dengan kelas" (protokol DetailDataStore: class), dan ini memerlukan banyak kesulitan, termasuk menangkap tautan yang kuat.

import UIKit
/// @objc
/// prepare View Controller'e
@objc protocol HomeRoutingLogic {
/// Detail View Controller
func routeToDetail(segue: UIStoryboardSegue?)
}
protocol HomeDataPassing {
var dataStore: HomeDataStore? { get }
}
final class HomeRouter: NSObject, HomeRoutingLogic, HomeDataPassing {
// MARK: - Private
// MARK: - Public
weak var viewController: HomeViewController?
var dataStore: HomeDataStore?
// MARK: - HomeRoutingLogic
func routeToDetail(segue: UIStoryboardSegue?) {
if let segue = segue {
//
// Segue
// Detail View Controller
// Data Store Router'e
guard
let homeDS = dataStore,
let detailVC = segue.destination as? DetailViewController,
var detailDS = detailVC.router?.dataStore
else { fatalError("Fail route to detail") }
// , , ,
// ""
passDataToDetail(source: homeDS, destination: &detailDS)
} else {
// ,
// Segue
// Detail View Controller Storyboard'a
// Data Store Router'e
guard
let viewController = viewController,
let homeDS = dataStore,
let storyboard = viewController.storyboard,
let detailVC = storyboard.instantiateViewController(withIdentifier: "Detail") as? DetailViewController,
var detailDS = detailVC.router?.dataStore
else { fatalError("Fail route to detail") }
passDataToDetail(source: homeDS, destination: &detailDS)
// , ""
navigateToDetail(source: viewController, destination: detailVC)
}
}
// MARK: - Navigation
private func navigateToDetail(source: HomeViewController, destination: DetailViewController) {
source.navigationController?.pushViewController(destination, animated: true)
}
// MARK: - Passing data
/// destination inout,
/// Data Store
private func passDataToDetail(source: HomeDataStore, destination: inout DetailDataStore) {
// HomeDataStore DetailDataStore
destination.message = source.message
}
}


Kesimpulan


Itu saja. Terima kasih sudah membaca sampai akhir! Di bawah ini saya akan meninggalkan tautan ke proyek jika Anda ingin mencoba artikel tersebut dalam tindakan.

Seri artikel


  1. Tinjauan Arsitektur Swift Bersih
  2. Router dan Passing Data dalam arsitektur Swift Bersih (Anda di sini)
  3. Pekerja Arsitektur Swift Bersih
  4. Pengujian unit dalam arsitektur Clean Swift
  5. Contoh arsitektur toko online sederhana Clean Swift

Tautan ke proyek
Bantuan dalam menulis artikel: Bastien

Source: https://habr.com/ru/post/id454032/


All Articles