Anda mendekatinya dengan cara yang salah: di Swift, tidak seperti Objective-C, kelas memiliki tipe tertentu dan bahkan memiliki hierarki warisan (yaitu, jika kelas Bmewarisi dari A, maka B.Typejuga mewarisi dari A.Type):
class A {}
class B: A {}
class C {}
// B inherits from A
let object: A = B()
// B.Type also inherits from A.Type
let type: A.Type = B.self
// Error: 'C' is not a subtype of 'A'
let type2: A.Type = C.self
Itu sebabnya Anda tidak boleh menggunakan AnyClass, kecuali Anda benar-benar ingin mengizinkan kelas apa pun . Dalam hal ini tipe yang tepat adalah T.Type, karena itu menyatakan hubungan antara returningClassparameter dan parameter penutupan.
Bahkan, menggunakannya bukan AnyClassmemungkinkan kompiler untuk menyimpulkan dengan benar jenis-jenis dalam pemanggilan metode:
class func invokeService<T>(service: String, withParams params: Dictionary<String, String>, returningClass: T.Type, completionHandler handler: ((T) -> ())) {
// The compiler correctly infers that T is the class of the instances of returningClass
handler(returningClass())
}
Sekarang ada masalah membangun instance Tuntuk dilewatkan handler: jika Anda mencoba dan menjalankan kode sekarang kompiler akan mengeluh bahwa Titu tidak dapat dibangun dengan (). Dan memang seharusnya begitu: Tharus dibatasi secara eksplisit untuk mengharuskannya mengimplementasikan inisialisasi tertentu.
Ini dapat dilakukan dengan protokol seperti berikut:
protocol Initable {
init()
}
class CityInfo : NSObject, Initable {
var cityName: String?
var regionCode: String?
var regionName: String?
// Nothing to change here, CityInfo already implements init()
}
Maka Anda hanya perlu mengubah batasan umum dari invokeServicedari <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:
let service = "test"
let params = ["test" : "test"]
let returningClass = CityInfo.self
CastDAO.invokeService(service, withParams: params, returningClass: returningClass) { cityInfo in /*...*/
}
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 Thanya digunakan dalam parameter penutupan dan penutupan yang Anda lewati tidak menunjukkan tipe tertentu sehingga kompiler tidak tahu tipe apa yang harus disimpulkan. Dengan mengubah tipe returningClassuntuk menyertakan TAnda memberi kompiler cara untuk menentukan parameter generik.
CastDAO.invokeService("test", withParams: ["test" : "test"]) { (ci:CityInfo) in }