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:
- Metode dari implementasi RoutingLogic (routeTo)
- Metode yang bertanggung jawab untuk navigasi (navigasikan ke, transisi tanpa Segue)
- 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
- Tinjauan Arsitektur Swift Bersih
- Router dan Passing Data dalam arsitektur Swift Bersih (Anda di sini)
- Pekerja Arsitektur Swift Bersih
- Pengujian unit dalam arsitektur Clean Swift
- Contoh arsitektur toko online sederhana Clean Swift
Tautan ke proyekBantuan dalam menulis artikel:
Bastien