Saya ingin membuat fungsi abstrak dalam bahasa cepat. Apa itu mungkin?
class BaseClass {
func abstractFunction() {
// How do I force this function to be overridden?
}
}
class SubClass : BaseClass {
override func abstractFunction() {
// Override
}
}
Jawaban:
Tidak ada konsep abstrak di Swift (seperti Objective-C) tetapi Anda dapat melakukan ini:
sumber
assert(false, "This method must be overriden by the subclass")
.fatalError("This method must be overridden")
preconditionFailure("Bla bla bla")
di Swift yang akan mengeksekusi dalam rilis build dan juga menghilangkan kebutuhan akan pernyataan return. EDIT: Baru tahu bahwa metode ini pada dasarnya sama denganfatalError()
tetapi ini cara yang lebih tepat (Dokumentasi yang lebih baik, diperkenalkan di Swift bersama denganprecondition()
,assert()
danassertionFailure()
, baca di sini )Yang Anda inginkan bukan kelas dasar, tetapi sebuah protokol.
Jika Anda tidak menyediakan Fungsi abstrak di kelas Anda itu adalah kesalahan.
Jika Anda masih membutuhkan baseclass untuk perilaku lain, Anda dapat melakukan ini:
sumber
Saya port cukup kode dari platform yang mendukung kelas dasar abstrak ke Swift dan menjalankan banyak ini. Jika yang Anda inginkan adalah fungsionalitas dari kelas dasar abstrak, maka itu berarti bahwa kelas ini berfungsi baik sebagai implementasi dari fungsi kelas berbasis bersama (jika tidak, itu hanya akan menjadi antarmuka / protokol) DAN itu mendefinisikan metode yang harus diimplementasikan oleh kelas turunan.
Untuk melakukannya di Swift, Anda memerlukan protokol dan kelas dasar.
Perhatikan bahwa kelas dasar mengimplementasikan metode bersama, tetapi tidak mengimplementasikan protokol (karena tidak menerapkan semua metode).
Kemudian di kelas turunan:
Kelas turunan mewarisi sharedFunction dari kelas dasar, membantunya memenuhi bagian protokol itu, dan protokol tersebut masih membutuhkan kelas turunan untuk mengimplementasikan fungsi abstrak.
Satu-satunya downside nyata untuk metode ini adalah bahwa karena kelas dasar tidak mengimplementasikan protokol, jika Anda memiliki metode kelas dasar yang membutuhkan akses ke properti / metode protokol Anda harus menimpa bahwa dalam kelas turunan, dan dari sana memanggil kelas dasar (melalui super) yang lewat
self
sehingga kelas dasar memiliki instance protokol yang dapat digunakan untuk melakukan tugasnya.Sebagai contoh, katakanlah bahwa sharedFunction diperlukan untuk memanggil abstractFunction. Protokol akan tetap sama, dan kelas sekarang akan terlihat seperti:
Sekarang sharedFunction dari kelas turunan memuaskan bagian protokol itu, tetapi kelas turunan masih dapat berbagi logika kelas dasar dengan cara yang cukup mudah.
sumber
Yang ini tampaknya menjadi cara "resmi" bagaimana Apple menangani metode abstrak di UIKit. Lihatlah
1. Masukkan metode abstrak dalam sebuah protokol 2. Tulis kelas dasar Anda 3. Tuliskan Subclass (es). Inilah, bagaimana Anda menggunakan semua ituUITableViewController
dan cara kerjanyaUITableViewDelegate
. Salah satu hal pertama yang Anda lakukan, adalah untuk menambahkan baris:delegate = self
. Nah, itulah triknya.Periksa dengan Playground untuk melihat hasilnya.
Beberapa komentar
UITableViewController
mengimplementasikanUITableViewDelegate
tetapi masih perlu didaftarkan sebagai delegasi dengan menetapkandelegate
properti secara eksplisit .sumber
getComments
metode pada delegasi induk. Ada beberapa jenis komentar, dan saya ingin yang relevan untuk setiap objek. Jadi, saya ingin subclass tidak dikompilasi ketika saya lakukandelegate.getComments()
jika saya tidak menimpa metode itu. VC hanya tahu ia memilikiParentDelegate
objek yang disebutdelegate
, atauBaseClassX
dalam contoh Anda, tetapiBaseClassX
tidak memiliki metode abstrak. Saya membutuhkan VC untuk secara khusus tahu bahwa itu menggunakanSubclassedDelegate
.Salah satu cara untuk melakukan ini adalah dengan menggunakan penutupan opsional yang ditentukan dalam kelas dasar, dan anak-anak dapat memilih untuk mengimplementasikannya atau tidak.
sumber
Yah, saya tahu bahwa saya terlambat ke permainan dan bahwa saya mungkin mengambil keuntungan dari perubahan yang telah terjadi. Maaf soal itu.
Bagaimanapun, saya ingin berkontribusi jawaban saya, karena saya suka melakukan pengujian dan solusinya
fatalError()
adalah, AFAIK, tidak dapat diuji dan yang dengan pengecualian jauh lebih sulit untuk diuji.Saya akan menyarankan untuk menggunakan lebih swifty pendekatan. Tujuan Anda adalah untuk mendefinisikan abstraksi yang memiliki beberapa detail umum, tetapi itu tidak sepenuhnya didefinisikan, yaitu metode abstrak. Gunakan protokol yang mendefinisikan semua metode yang diharapkan dalam abstraksi, baik yang sudah didefinisikan, maupun yang tidak. Kemudian buat ekstensi protokol yang mengimplementasikan metode yang didefinisikan dalam kasus Anda. Akhirnya, setiap kelas turunan harus mengimplementasikan protokol, yang berarti semua metode, tetapi yang merupakan bagian dari ekstensi protokol sudah memiliki implementasinya.
Memperluas contoh Anda dengan satu fungsi konkret:
Perhatikan bahwa dengan melakukan ini, kompiler adalah lagi teman Anda. Jika metode ini tidak "diganti", Anda akan mendapatkan kesalahan pada waktu kompilasi, alih-alih yang Anda akan dapatkan
fatalError()
atau pengecualian yang akan terjadi pada waktu berjalan.sumber
Saya mengerti apa yang Anda lakukan sekarang, saya pikir Anda akan lebih baik menggunakan protokol
Kemudian, Anda cukup mematuhi protokol:
Jika kelas Anda juga merupakan subkelas, protokol ikuti Superclass:
sumber
Menggunakan
assert
kata kunci untuk menegakkan metode abstrak:Namun, seperti yang disebutkan Steve Waddicor, Anda mungkin menginginkannya
protocol
.sumber
Saya mengerti pertanyaan itu dan sedang mencari solusi yang sama. Protokol tidak sama dengan metode abstrak.
Dalam protokol Anda perlu menentukan bahwa kelas Anda sesuai dengan protokol tersebut, metode abstrak berarti bahwa Anda harus mengganti metode tersebut.
Dengan kata lain, protokol adalah jenis opsional, Anda perlu menentukan kelas dasar dan protokol, jika Anda tidak menentukan protokol, maka Anda tidak perlu menimpa metode tersebut.
Metode abstrak berarti Anda menginginkan kelas dasar tetapi perlu menerapkan metode Anda sendiri atau dua, yang tidak sama.
Saya membutuhkan perilaku yang sama, itu sebabnya saya mencari solusi. Saya kira Swift tidak memiliki fitur tersebut.
sumber
Ada alternatif lain untuk masalah ini, meskipun masih ada kelemahan jika dibandingkan dengan proposal @ jaumard; itu membutuhkan pernyataan pengembalian. Meskipun saya kehilangan titik memerlukannya, karena itu terdiri dari langsung melemparkan pengecualian:
Lalu:
Apa pun yang terjadi setelah itu tidak dapat dijangkau, jadi saya tidak melihat mengapa memaksakan pengembalian.
sumber
AbstractMethodException().raise()
?Saya tidak tahu apakah ini akan berguna, tetapi saya memiliki masalah serupa dengan metode abstrak saat mencoba membangun game SpritKit. Apa yang saya inginkan adalah kelas Animal abstrak yang memiliki metode seperti move (), run () dll, tetapi nama sprite (dan fungsi lainnya) harus disediakan oleh anak-anak kelas. Jadi saya akhirnya melakukan sesuatu seperti ini (diuji untuk Swift 2):
sumber