Swift: Tetapkan sebuah instance dari tipe generik ke variabel kelas?
Saya mencoba menggunakan ini https://github.com/bricklife/JSONRPCKit. Ini adalah implementasi sederhana JSONRPC untuk Swift.
Ini adalah contoh di readme. Cukup sederhana.
// Generating request JSON
let batchFactory = BatchFactory(version: "2.0", idGenerator: NumberIdGenerator())
let request = Subtract(minuend: 42, subtrahend: 23)
let batch = batchFactory.create(request)
batch.requestObject // ["jsonrpc": "2.0", "method": "subtract", "params": [42, 23], "id": 1]
// Parsing response JSON
let responseObject: Any = ["jsonrpc": "2.0", "result": 19, "id": 1]
let response = try! batch.responses(from: responseObject)
Saya ingin melacak batch
, bahkan jika itu dibuat dalam fungsi kelas. Sehingga berfungsi lain (ketika saya mendapat balasan dari server saya). Dapat mengakses permintaan / batch / batchelement spesifik dan menjalankan fungsi apa pun yang diperlukan.
Saya tidak dapat membuat vars di kelas saya menggunakan salah satu jenis dari JSONRPCKit.
Saya mendapatkan kesalahan kompiler di sepanjang baris:
Protokol 'Batch' hanya dapat digunakan sebagai batasan umum karena memiliki persyaratan tipe Self atau terkait
Referensi ke tipe generik 'Batch1' membutuhkan argumen di <...>
Nilai tipe protokol 'Request' tidak bisa mengikuti 'Request'; hanya tipe struct / enum / class yang dapat mengikuti protokol
Saya mencoba menggunakan generik dalam fungsi entah bagaimana untuk menghindari masalah saya tetapi itu juga tidak membantu.
func store_b<Batch: JSONRPCKit.Batch>(_ batch: Batch){
Info lebih lanjut: batch
bertipe Batch1
, seperti:
public struct Batch1<Request: JSONRPCKit.Request>: Batch {
dan Batch
merupakan protokol
public protocol Batch {
Apakah ada cara sederhana untuk melacak batch
permintaan saya dan mendapatkan tanggapan / bagaimana saya menggunakan obat generik ini dengan benar?
Jawaban
Hancurkan tanda tangan metode pembuatan dan tipe Batch1
public func create<Request: JSONRPCKit.Request>(_ request: Request) -> Batch1<Request>
public struct Batch1<Request: JSONRPCKit.Request>: Batch {
public typealias Responses = Request.Response
public typealias Results = Result<Request.Response, JSONRPCError>
}
create
adalah fungsi umum yang menggunakan satu parameter jenis apa pun . Batasan <Request: JSONRPCKit.Request>
menentukan bahwa jenis parameter harus sesuai dengan protokol JSONRPCKit.Request
.
Batch1
adalah struct umum yang perlu mendefinisikan dua tipe internal, keduanya terkait dengan beberapa tipe arbitrer . Sekali lagi, <Request: JSONRPCKit.Request>
tentukan bahwa jenis arbitrer harus sesuai dengan protokol JSONRPCKit.Request
.
Jenis yang dikembalikan Batch1<Request>
mengikat kedua generik ini bersama-sama, mengatakan bahwa jenis yang digunakan untuk Batch1
struct yang dikembalikan akan cocok dengan jenis request
parameter.
Saat Anda memanggil metode create, Anda harus mengisi tipe generik dengan tipe konkret, seperti pada contoh
let batch = batchFactory.create(Subtract(minuend: 42, subtrahend: 23))
Sekarang kompilator dapat memeriksa semua definisi dan membuat implementasi konkret untuk jenis itu:
public func create(_ request: Subtract) -> Batch1<Subtract>
public struct Batch1<Subtract>: Batch {
public typealias Responses = Int
public typealias Results = Result<Int, JSONRPCError>
}
Ini menggunakan fakta yang Subtract
mendefinisikan typealias Response = Int
. Perhatikan bahwa tidak ada yang generik lagi; ini semua adalah tipe beton. Anda tidak akan kesulitan mencoba menyimpan properti bertipe Batch1<Subtract>
.
Inilah sebabnya mengapa Anda tidak dapat dengan mudah menyimpan batch di properti: Swift tidak tahu tipe apa yang harus dimasukkan ke dalamnya!
Salah satu cara untuk mengatasinya adalah dengan menyimpan closure, ini bisa membungkus batch generik sehingga kelas tidak perlu mengetahuinya
// closure property
var responseProcessor: ((Any) -> Void)?
func createBatch<R: JSONRPCKit.Request>(request: R, processor: @escaping (R.Response) -> Void) {
let batch = batchFactory.create(request)
self.responseProcessor = { responseObject in
let response = try! batch.responses(from: responseObject)
processor(response)
}
}
// somewhere else when you get the responseObject
responseProcessor?(responseObject)
Metode ini mengambil closure spesifik yang cocok dengan tipe generik dan membungkusnya dalam closure yang tidak lagi bergantung pada generik. Dengan cara ini setiap batch dapat berbagi properti closure yang sama.