Saya memiliki fungsi generik yang memanggil layanan web dan membuat serialisasi respons JSON kembali ke objek.
class func invokeService<T>(service: String, withParams params: Dictionary<String, String>, returningClass: AnyClass, completionHandler handler: ((T) -> ())) {
/* Construct the URL, call the service and parse the response */
}
Apa yang saya coba capai adalah setara dengan kode Java ini
public <T> T invokeService(final String serviceURLSuffix, final Map<String, String> params,
final Class<T> classTypeToReturn) {
}
- Apakah tanda tangan metode saya untuk apa yang saya coba selesaikan dengan benar?
- Lebih khusus lagi, apakah menetapkan
AnyClass
sebagai parameter adalah hal yang benar untuk dilakukan? - Saat memanggil metode, saya meneruskan
MyObject.self
sebagai nilai returnsClass, tapi saya mendapatkan kesalahan kompilasi "Tidak dapat mengonversi tipe ekspresi '()' untuk mengetikkan 'String'"
CastDAO.invokeService("test", withParams: ["test" : "test"], returningClass: CityInfo.self) { cityInfo in /*...*/
}
Edit:
Saya mencoba menggunakan object_getClass
, seperti yang disebutkan oleh holex, tetapi sekarang saya mendapatkan:
galat: "Ketik 'CityInfo.Type' tidak sesuai dengan protokol 'AnyObject'"
Apa yang perlu dilakukan agar sesuai dengan protokol?
class CityInfo : NSObject {
var cityName: String?
var regionCode: String?
var regionName: String?
}
swift
generics
type-inference
Jean-Francois Gagnon
sumber
sumber
CastDAO.invokeService("test", withParams: ["test" : "test"]) { (ci:CityInfo) in }
Jawaban:
Anda mendekatinya dengan cara yang salah: di Swift, tidak seperti Objective-C, kelas memiliki tipe tertentu dan bahkan memiliki hierarki warisan (yaitu, jika kelas
B
mewarisi dariA
, makaB.Type
juga mewarisi dariA.Type
):Itu sebabnya Anda tidak boleh menggunakan
AnyClass
, kecuali Anda benar-benar ingin mengizinkan kelas apa pun . Dalam hal ini tipe yang tepat adalahT.Type
, karena itu menyatakan hubungan antarareturningClass
parameter dan parameter penutupan.Bahkan, menggunakannya bukan
AnyClass
memungkinkan kompiler untuk menyimpulkan dengan benar jenis-jenis dalam pemanggilan metode:Sekarang ada masalah membangun instance
T
untuk dilewatkanhandler
: jika Anda mencoba dan menjalankan kode sekarang kompiler akan mengeluh bahwaT
itu tidak dapat dibangun dengan()
. Dan memang seharusnya begitu:T
harus dibatasi secara eksplisit untuk mengharuskannya mengimplementasikan inisialisasi tertentu.Ini dapat dilakukan dengan protokol seperti berikut:
Maka Anda hanya perlu mengubah batasan umum dari
invokeService
dari<T>
menjadi<T: Initable>
.Tip
Jika Anda mendapatkan kesalahan aneh seperti "Tidak dapat mengonversi tipe ekspresi '()' menjadi tipe 'String'", sering kali berguna untuk memindahkan setiap argumen pemanggilan metode ke variabelnya sendiri. Ini membantu mempersempit kode yang menyebabkan kesalahan dan mengungkap masalah jenis inferensi:
Sekarang ada dua kemungkinan: kesalahan berpindah ke salah satu variabel (yang berarti ada bagian yang salah di sana) atau Anda mendapatkan pesan samar seperti "Tidak dapat mengonversi jenis ekspresi
()
ke jenis($T6) -> ($T6) -> $T5
".Penyebab kesalahan terakhir adalah bahwa kompiler tidak dapat menyimpulkan jenis dari apa yang Anda tulis. Dalam hal ini masalahnya adalah yang
T
hanya digunakan dalam parameter penutupan dan penutupan yang Anda lewati tidak menunjukkan tipe tertentu sehingga kompiler tidak tahu tipe apa yang harus disimpulkan. Dengan mengubah tipereturningClass
untuk menyertakanT
Anda memberi kompiler cara untuk menentukan parameter generik.sumber
T
digunakan untuk menyatakan hubungan antara objekreturningClass
dan yang diteruskan kecompletionHandler
. JikaInitiable.Type
digunakan hubungan ini hilang.func somefunc<U>()
Anda bisa mendapatkan kelas
AnyObject
melalui cara ini:Cepat 3.x
Swift 2.x
dan Anda dapat meneruskannya sebagai paramater nanti, jika Anda mau.
sumber
self.dynamicType
Saya memiliki kasus penggunaan serupa di swift5:
sumber
Static method … requires that 'MyDecodable.Type' conform to 'Decodable'
. Maukah Anda memperbarui jawaban Anda untuk memberikan contoh panggilanloadItem
?.Type
dan.self
(tipe dan metatype).Gunakan
obj-getclass
:Anggap diri adalah objek info kota.
sumber
Cepat 5
Situasi yang tidak persis sama, tetapi saya mengalami masalah yang sama. Yang akhirnya membantu saya adalah ini:
Kemudian Anda bisa menyebutnya di dalam instance dari kelas kata seperti ini:
Semoga ini bisa membantu seseorang dalam situasi yang sama dengan saya.
sumber