Tinjauan Arsitektur Swift Bersih

Halo pembaca!

Pada artikel ini saya akan berbicara tentang arsitektur aplikasi iOS - Clean Swift . Kami akan mempertimbangkan poin teoritis utama dan menganalisis contoh dalam praktik.



Teori


Untuk memulai, kita akan menganalisis terminologi dasar arsitektur. Di Bersihkan Swift, aplikasi terdiri dari adegan, mis. setiap layar aplikasi adalah satu adegan. Interaksi utama dalam adegan melalui loop berurutan antara komponen ViewController -> Interactor -> Presenter . Ini disebut siklus VIP .

Jembatan antara komponen adalah file Model , yang menyimpan data yang dikirim. Ada juga Router yang bertanggung jawab untuk mentransfer dan mentransfer data antara adegan, dan Worker , yang mengambil alih bagian dari logika Interactor'a .



Lihat


Storyboard, XIB, atau elemen UI ditulis melalui kode.

ViewController


Hanya bertanggung jawab untuk konfigurasi dan interaksi dengan View . Pengontrol tidak boleh berisi logika bisnis, interaksi jaringan, komputasi, dan sebagainya.
Tugasnya adalah untuk memproses acara dengan Lihat , tampilkan atau kirim data (tanpa pemrosesan dan pemeriksaan) di Interactor .

Interactractor


Ini berisi logika bisnis tempat kejadian.

Ini bekerja dengan modul jaringan, basis data dan perangkat.

Interactor menerima permintaan dari ViewController (dengan data atau kosong), memprosesnya dan, jika perlu, mentransfer data baru ke Presenter .

Presenter


Dia terlibat dalam persiapan data untuk ditampilkan.

Sebagai contoh, tambahkan topeng ke nomor telepon atau buat huruf pertama di judul modal.
Ini memproses data yang diterima dari Interactor , dan kemudian mengirimkannya kembali ke ViewController .

Model


Seperangkat struktur untuk mentransfer data antara komponen-komponen dari siklus VIP . Setiap lingkaran siklus memiliki 3 jenis struktur:

  • Permintaan - Struktur data (teks dari TextField, dll.) Untuk ditransfer dari ViewController ke Interactor
  • Respons - Struktur dengan data (diunduh dari jaringan, dll.) Untuk ditransfer dari Interactor ke Presenter
  • ViewModel - Struktur dengan data yang diproses (pemformatan teks, dll.) Di Presenter untuk mentransfer kembali ke ViewController

Pekerja


Membongkar Interactor , mengambil bagian dari logika bisnis aplikasi jika Interactor berkembang pesat.

Anda juga dapat membuat Pekerja yang umum untuk semua adegan, jika fungsinya digunakan di beberapa adegan.

Sebagai contoh, di Worker, Anda bisa membuat logika bekerja dengan jaringan atau database.

Router


Semua logika yang bertanggung jawab untuk transisi dan transfer data antara adegan diambil di Router .



Untuk memperjelas gambar siklus VIP , saya akan memberikan contoh standar - otorisasi.

  1. Pengguna memasukkan nama pengguna dan kata sandinya, mengklik tombol otorisasi
  2. ViewController memicu IBAction , setelah itu struktur dibuat dengan data pengguna dimasukkan ke dalam TextFields, (Model -> Permintaan)
  3. Struktur yang dibuat diteruskan ke metode fetchUser di Interactor'e
  4. Interactor mengirimkan permintaan ke jaringan dan menerima tanggapan tentang keberhasilan otorisasi
  5. Berdasarkan data yang diterima, buat struktur dengan hasil (Model -> Respons) dan diteruskan ke metode presentUser di Presenter'e
  6. Presenter memformat data sesuai kebutuhan dan mengembalikannya (Model -> ViewModel) ke metode displayUser di ViewController'e
  7. ViewController menampilkan data yang diterima kepada pengguna. Dalam kasus otorisasi, kesalahan dapat ditampilkan atau transisi ke adegan lain dapat dipicu menggunakan Router

Dengan demikian, kami mendapatkan struktur tunggal dan konsisten, dengan distribusi tanggung jawab menjadi komponen.

Berlatih


Sekarang mari kita lihat contoh praktis kecil yang menunjukkan bagaimana siklus VIP berjalan. Dalam contoh ini, kami akan mensimulasikan pemuatan data saat membuka adegan (layar). Saya menandai bagian utama dari kode dengan komentar.

Seluruh siklus VIP terkait dengan protokol, yang menyediakan kemampuan untuk mengganti modul apa pun tanpa mengganggu aplikasi.
Protokol DisplayLogic dibuat untuk ViewController , tautan yang diteruskan ke Presenter untuk dipanggil nanti. Untuk Interactor , dua protokol BusinessLogic dibuat, yang bertanggung jawab untuk memanggil metode dari ViewController , dan DataSource , untuk menyimpan data dan mentransfer adegan lain melalui Router ke Interactor . Presenter berlangganan protokol PresentationLogic untuk panggilan dari Interactor . Elemen penghubung dari semua ini adalah Model . Ini berisi struktur dengan bantuan pertukaran informasi antara komponen-komponen dari siklus VIP . Kami akan memulai analisis kode dengan itu.



Model


Pada contoh di bawah ini, untuk adegan Home , saya membuat file HomeModels yang berisi serangkaian pertanyaan untuk loop VIP .
Permintaan FetchUser akan bertanggung jawab untuk memuat data pengguna, yang akan kami pertimbangkan lebih lanjut.

// Models
/// VIP
enum HomeModels {
/// VIP
enum FetchUser {
/// Interactor View Controller
struct Request {
let userName: String
}
/// Presentor Interactor
struct Response {
let userPhone: String
let userEmail: String
}
/// View Controller Presentor
struct ViewModel {
let userPhone: String
let userEmail: String
}
}
}

ViewController


Ketika kelas diinisialisasi, kami instantiate kelas Interactor dan Presenter adegan ini dan membangun dependensi di antara mereka.
Lebih jauh di ViewController'e hanya ada tautan ke Interactor . Dengan menggunakan tautan ini, kami akan membuat permintaan ke metode fetchUser (request :) di Interactor untuk memulai siklus VIP .

Di sini perlu diperhatikan bagaimana permintaan kepada Interactor terjadi. Dalam metode loadUserInfromation () , kami membuat turunan dari struktur Permintaan , tempat kami meneruskan nilai awal. Itu bisa diambil dari TextField , tabel, dan sebagainya. Sebuah instance dari struktur Permintaan diteruskan ke metode fetchUser (request :) , yang ada dalam protokol BusinessLogic dari Interactor kami.

// ViewController
///
protocol HomeDisplayLogic: class {
///
func displayUser(_ viewModel: HomeModels.FetchUser.ViewModel)
}
final class HomeViewController: UIViewController {
/// Interactor'a
var interactor: HomeBusinessLogic?
override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) {
super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
setup()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
setup()
}
///
private func setup() {
// VIP
let interactor = HomeInteractor()
let presenter = HomePresenter()
//
interactor.presenter = presenter
presenter.viewController = self
// Interactor View Controller
self.interactor = interactor
}
override func viewDidLoad() {
super.viewDidLoad()
//
fetchUser()
}
/// Interactor
private func loadUserInfromation() {
// Interactor
let request = HomeModels.FetchUser.Request(userName: "Aleksey")
// Interactor'a
interactor?.fetchUser(request)
}
}
/// HomeDisplayLogic
extension HomeViewController: HomeDisplayLogic {
func displayUser(_ viewModel: HomeModels.FetchUser.ViewModel) {
print(viewModel)
}
}

Interactractor


Sebuah instance dari kelas Interactor berisi tautan ke protokol PresentationLogic , di mana Presenter ditandatangani.

Metode fetchUser (request :) dapat berisi logika pemuatan data apa pun. Misalnya, saya baru saja membuat konstanta, dengan data yang seharusnya diperoleh.

Dalam metode yang sama, sebuah instance dari struktur Response dibuat dan diisi dengan parameter yang diperoleh sebelumnya. Respons diteruskan ke PresentationLogic menggunakan metode presentUser (response :) . Dengan kata lain, di sini kami mendapatkan data mentah dan meneruskannya ke Presenter untuk diproses.

// Interactor
/// Interactor'a
protocol HomeBusinessLogic: class {
///
func fetchUser(_ request: HomeModels.FetchUser.Request)
}
final class HomeInteractor: HomeBusinessLogic {
///
var presenter: HomePresentationLogic?
func fetchUser(_ request: HomeModels.FetchUser.Request) {
//
//
let userPhone = "+7 (999) 111-22-33"
let userEmail = "im@alekseypleshkov.ru"
// ...
// Presentor'
let response = HomeModels.FetchUser.Response(userPhone: userPhone, userEmail: userEmail)
// Presentor'
presenter?.presentUser(response)
}
}

Presenter


Ini memiliki tautan ke protokol DisplayLogic , di mana ViewController ditandatangani. Itu tidak mengandung logika bisnis, tetapi hanya memformat data yang diterima sebelum menampilkannya. Dalam contoh ini, kami memformat nomor telepon, menyiapkan instance dari struktur ViewModel , dan meneruskannya ke ViewController menggunakan metode displayUser (viewModel :) dalam protokol DisplayLogic , di mana data sudah ditampilkan.

///
protocol HomePresentationLogic: class {
/// Interactor'a
func presentUser(_ response: HomeModels.FetchUser.Response)
}
final class HomePresenter: HomePresentationLogic {
/// View Controller'a
weak var viewController: HomeDisplayLogic?
func presentUser(_ response: HomeModels.FetchUser.Response) {
//
let formattedPhone = response.userPhone.replacingOccurrences(of: "-", with: " ")
// ViewModel View Controller
let viewModel = HomeModels.FetchUser.ViewModel(userPhone: formattedPhone, userEmail: response.userEmail)
// View Controller'a
viewController?.displayUser(viewModel)
}
}

Kesimpulan


Dengan arsitektur ini, kami mendapat kesempatan untuk mendistribusikan tanggung jawab, meningkatkan kenyamanan pengujian aplikasi, memperkenalkan penggantian bagian individu dari implementasi dan standar untuk menulis kode untuk bekerja dalam tim.

Terima kasih sudah membaca sampai akhir.

Seri artikel


  1. Memahami Arsitektur Swift Bersih (You Are Here)
  2. Router dan Passing Data dalam Arsitektur Swift Bersih
  3. Pekerja Arsitektur Swift Bersih
  4. Pengujian unit dalam arsitektur Clean Swift
  5. Contoh arsitektur toko online sederhana Clean Swift

Semua komponen adegan: Tautan
Bantuan dalam menulis artikel: Bastien

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


All Articles