Perpustakaan manajemen ketergantungan yang terinspirasi oleh "lingkungan" SwiftUi.
Perpustakaan ini termotivasi dan dirancang selama banyak episode di Point-Free, sebuah seri video yang mengeksplorasi pemrograman fungsional dan bahasa Swift, yang diselenggarakan oleh Brandon Williams dan Stephen Celis.
Ketergantungan adalah jenis dan fungsi dalam aplikasi Anda yang perlu berinteraksi dengan sistem luar yang tidak Anda kendalikan. Contoh klasik dari ini adalah klien API yang membuat permintaan jaringan ke server, tetapi juga hal -hal yang tampaknya tidak berbahaya seperti inisialisasi UUID
dan Date
, akses file, default pengguna, dan bahkan jam dan pengatur waktu, semuanya dapat dianggap sebagai dependensi.
Anda bisa menjadi sangat jauh dalam pengembangan aplikasi tanpa pernah memikirkan manajemen ketergantungan (atau, seperti beberapa orang suka menyebutnya, "injeksi ketergantungan"), tetapi pada akhirnya ketergantungan yang tidak terkendali dapat menyebabkan banyak masalah dalam basis kode dan siklus pengembangan Anda:
Ketergantungan yang tidak terkendali membuat sulit untuk menulis tes deterministik yang cepat karena Anda rentan terhadap keanehan dunia luar, seperti sistem file, konektivitas jaringan, kecepatan internet, uptime server, dan banyak lagi.
Banyak ketergantungan tidak bekerja dengan baik dalam pratinjau SwiftUi , seperti manajer lokasi dan pengenal ucapan, dan beberapa tidak bekerja bahkan dalam simulator , seperti manajer gerak, dan banyak lagi. Ini mencegah Anda dari dapat dengan mudah mengulangi desain fitur jika Anda memanfaatkan kerangka kerja tersebut.
Ketergantungan yang berinteraksi dengan pihak ke-3, perpustakaan non-apple (seperti firebase, perpustakaan web soket, perpustakaan jaringan, dll.) Cenderung kelas berat dan membutuhkan waktu lama untuk dikompilasi . Ini dapat memperlambat siklus pengembangan Anda.
Karena alasan ini, dan lebih banyak lagi, sangat dianjurkan bagi Anda untuk mengendalikan ketergantungan Anda daripada membiarkan mereka mengendalikan Anda.
Tapi, mengendalikan ketergantungan hanyalah awal. Setelah Anda mengendalikan dependensi, Anda dihadapkan dengan seluruh rangkaian masalah baru:
Bagaimana Anda dapat menyebarkan ketergantungan di seluruh aplikasi Anda dengan cara yang lebih ergonomis daripada secara eksplisit melewatinya di mana -mana, tetapi lebih aman daripada memiliki ketergantungan global?
Bagaimana Anda bisa mengganti dependensi hanya untuk satu bagian dari aplikasi Anda? Ini bisa berguna untuk ketergantungan utama untuk tes dan pratinjau SwiftUi, serta aliran pengguna tertentu seperti pengalaman onboarding.
Bagaimana Anda bisa yakin Anda mengesampingkan semua dependensi yang digunakan fitur dalam tes? Akan salah untuk tes untuk mengejek beberapa ketergantungan tetapi membuat yang lain berinteraksi dengan dunia luar.
Perpustakaan ini membahas semua poin di atas, dan banyak lagi.
Perpustakaan memungkinkan Anda untuk mendaftarkan ketergantungan Anda sendiri, tetapi juga dilengkapi dengan banyak dependensi yang dapat dikendalikan dari kotak (lihat DependencyValues
untuk daftar lengkap), dan ada peluang bagus Anda dapat segera memanfaatkannya. Jika Anda menggunakan Date()
, UUID()
, Task.sleep
@ Observable
final class FeatureModel {
var items : [ Item ] = [ ]
@ ObservationIgnored
@ Dependency ( . continuousClock ) var clock // Controllable way to sleep a task
@ ObservationIgnored
@ Dependency ( . date . now ) var now // Controllable way to ask for current date
@ ObservationIgnored
@ Dependency ( . mainQueue ) var mainQueue // Controllable scheduling on main queue
@ ObservationIgnored
@ Dependency ( . uuid ) var uuid // Controllable UUID creation
// ...
}
Setelah dependensi Anda dinyatakan, daripada menjangkau Date()
, UUID()
, dll., Secara langsung, Anda dapat menggunakan ketergantungan yang didefinisikan pada model fitur Anda:
@ Observable
final class FeatureModel {
// ...
func addButtonTapped ( ) async throws {
try await clock . sleep ( for : . seconds ( 1 ) ) // ? Don't use 'Task.sleep'
items . append (
Item (
id : uuid ( ) , // ? Don't use 'UUID()'
name : " " ,
createdAt : now // ? Don't use 'Date()'
)
)
}
}
Hanya itu yang diperlukan untuk mulai menggunakan dependensi yang dapat dikendalikan dalam fitur Anda. Dengan sedikit pekerjaan di muka yang dilakukan, Anda dapat mulai memanfaatkan kekuatan perpustakaan.
Misalnya, Anda dapat dengan mudah mengontrol ketergantungan ini dalam tes. Jika Anda ingin menguji logika di dalam metode addButtonTapped
, Anda dapat menggunakan fungsi withDependencies
untuk mengganti ketergantungan apa pun untuk ruang lingkup satu tes tunggal. Semudah 1-2-3:
@ Test
func add ( ) async throws {
let model = withDependencies {
// 1️⃣ Override any dependencies that your feature uses.
$0 . clock = . immediate
$0 . date . now = Date ( timeIntervalSinceReferenceDate : 1234567890 )
$0 . uuid = . incrementing
} operation : {
// 2️⃣ Construct the feature's model
FeatureModel ( )
}
// 3️⃣ The model now executes in a controlled environment of dependencies,
// and so we can make assertions against its behavior.
try await model . addButtonTapped ( )
#expect (
model . items == [
Item (
id : UUID ( uuidString : " 00000000-0000-0000-0000-000000000000 " ) ! ,
name : " " ,
createdAt : Date ( timeIntervalSinceReferenceDate : 1234567890 )
)
]
)
}
Di sini kami mengendalikan ketergantungan date
untuk selalu mengembalikan tanggal yang sama, dan kami mengendalikan ketergantungan uuid
untuk mengembalikan UUID yang meningkat secara otomatis setiap kali dipanggil, dan kami bahkan mengendalikan ketergantungan clock
menggunakan lock ImmediateClock
untuk meremas sepanjang waktu menjadi satu kali ke dalam satu kali menjadi satu ke dalam satu kali ke dalam satu kali menjadi satu ke dalam satu kali menjadi satu ke dalam satu kali ke dalam satu kali menjadi satu ke dalam satu kali ke dalam satu kali menjadi satu ke dalam satu kali menjadi satu ke dalam satu kali menjadi satu ke dalam satu kali menjadi satu ke dalam satu kali menjadi satu ke dalam satu kali menjadi satu ke dalam satu kali ke dalam satu kali menjadi satu ke dalam satu kali ke dalam satu kali menjadi satu ke dalam satu kali ke dalam satu kali menjadi satu ke dalam satu kali ke dalam satu kali menjadi satu ke dalam satu ke dalam satu kali menjadi satu ke dalam satu kali menjadi satu ke dalam satu kali ke dalam satu kali menjadi satu ke dalam satu kali ke dalam satu ke dalam satu ke dalam satu ke dalam satu ke dalam satu ke dalam satu kali menjadi satu ke dalam satu ke dalam satu ke dalam satu ke dalam instan. Jika kami tidak mengontrol dependensi ini tes ini akan sangat sulit untuk ditulis karena tidak ada cara untuk memprediksi secara akurat apa yang akan dikembalikan berdasarkan Date()
dan UUID()
, dan kami harus menunggu waktu dunia nyata untuk lewat, membuat tes lambat.
Tetapi, dependensi yang dapat dikendalikan tidak hanya berguna untuk tes. Mereka juga dapat digunakan dalam pratinjau Xcode. Misalkan fitur di atas memanfaatkan jam untuk tidur selama beberapa waktu sebelum sesuatu terjadi dalam pandangan. Jika Anda tidak ingin benar -benar menunggu waktu untuk melewati untuk melihat bagaimana tampilan berubah, Anda dapat mengesampingkan ketergantungan jam menjadi jam "langsung" menggunakan sifat pratinjau .dependencies
Dependensi:
#Preview (
traits : . dependencies {
$0 . continuousClock = . immediate
}
) {
// All access of '@Dependency(.continuousClock)' in this preview will
// use an immediate clock.
FeatureView ( model : FeatureModel ( ) )
}
Ini akan membuatnya sehingga pratinjau menggunakan jam langsung saat dijalankan, tetapi saat berjalan dalam simulator atau di perangkat itu masih akan menggunakan live ContinuousClock
langsung. Ini memungkinkan untuk mengganti dependensi hanya untuk pratinjau tanpa mempengaruhi bagaimana aplikasi Anda akan berjalan dalam produksi.
Itulah dasar -dasar untuk memulai dengan menggunakan perpustakaan, tetapi masih ada banyak lagi yang dapat Anda lakukan. Anda dapat mempelajari lebih lanjut secara mendalam tentang perpustakaan dengan menjelajahi dokumentasi dan artikel:
Mulai cepat (sama seperti informasi di atas) : Pelajari dasar -dasar memulai dengan perpustakaan sebelum menyelam jauh ke dalam semua fitur -fiturnya.
Apa itu dependensi? : Pelajari apa ketergantungan itu, bagaimana mereka mempersulit kode Anda, dan mengapa Anda ingin mengendalikannya.
Menggunakan dependensi : Pelajari cara menggunakan dependensi yang terdaftar di perpustakaan.
Mendaftarkan Ketergantungan : Pelajari cara mendaftarkan dependensi Anda sendiri dengan perpustakaan sehingga mereka segera tersedia dari bagian mana pun dari basis kode Anda.
Ketergantungan langsung, pratinjau, dan pengujian : Pelajari cara memberikan berbagai implementasi dependensi Anda untuk digunakan dalam aplikasi langsung, serta dalam pratinjau Xcode, dan bahkan dalam pengujian.
Pengujian : Salah satu alasan utama untuk mengendalikan dependensi adalah untuk memungkinkan pengujian yang lebih mudah. Pelajari beberapa tips dan trik untuk menulis tes yang lebih baik dengan perpustakaan.
Merancang dependensi : Pelajari teknik untuk merancang dependensi Anda sehingga mereka paling fleksibel untuk menyuntikkan ke dalam fitur dan mengesampingkan tes.
Ketergantungan utama : Pelajari bagaimana dependensi dapat diubah saat runtime sehingga bagian -bagian tertentu dari aplikasi Anda dapat menggunakan dependensi yang berbeda.
Lifetimes Ketergantungan : Pelajari tentang masa hidup ketergantungan, bagaimana memperpanjang masa pakai ketergantungan, dan bagaimana ketergantungan diwarisi.
Sistem titik masuk tunggal : Pelajari tentang sistem "titik masuk tunggal", dan mengapa mereka paling cocok untuk perpustakaan dependensi ini, meskipun dimungkinkan untuk menggunakan perpustakaan dengan sistem titik masuk non-single.
Kami membangun kembali aplikasi demo Scrumdinger Apple menggunakan praktik modern, terbaik untuk pengembangan SwiftUI, termasuk menggunakan perpustakaan ini untuk mengontrol dependensi pada akses sistem file, pengatur waktu, dan API pengenalan suara. Demo itu dapat ditemukan di sini.
Dokumentasi terbaru untuk API dependensi tersedia di sini.
Anda dapat menambahkan dependensi ke proyek XCode dengan menambahkannya ke proyek Anda sebagai paket.
https://github.com/pointfreeco/swift-dependencies
Jika Anda ingin menggunakan dependensi dalam proyek SwiftPM, itu sesederhana menambahkannya ke Package.swift
Anda.
dependencies: [
. package ( url : " https://github.com/pointfreeco/swift-dependencies " , from : " 1.0.0 " )
]
Dan kemudian menambahkan produk ke target apa pun yang membutuhkan akses ke perpustakaan:
. product ( name : " Dependencies " , package : " swift-dependencies " ) ,
Jika Anda ingin mendiskusikan perpustakaan ini atau memiliki pertanyaan tentang cara menggunakannya untuk menyelesaikan masalah tertentu, ada sejumlah tempat yang dapat Anda diskusikan dengan sesama penggemar bebas poin:
Perpustakaan ini mengontrol sejumlah dependensi di luar kotak, tetapi juga terbuka untuk ekstensi. Proyek -proyek berikut semuanya dibangun di atas dependensi:
Ada banyak perpustakaan injeksi ketergantungan lainnya di komunitas Swift. Masing-masing memiliki serangkaian prioritas dan trade-off sendiri yang berbeda dari dependensi. Berikut adalah beberapa contoh terkenal:
Perpustakaan ini dirilis di bawah lisensi MIT. Lihat lisensi untuk detailnya.