Swift: กำหนดอินสแตนซ์ของประเภททั่วไปให้กับตัวแปรคลาส?
ฉันกำลังพยายามใช้สิ่งนี้ https://github.com/bricklife/JSONRPCKit. เป็นการนำ JSONRPC สำหรับ Swift ไปใช้งานง่ายๆ
นี่คือตัวอย่างใน readme ค่อนข้างง่าย
// 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)
ฉันต้องการติดตามbatch
แม้ว่ามันจะถูกสร้างขึ้นในฟังก์ชันของคลาสก็ตาม เพื่อให้ฟังก์ชั่นอื่น (เมื่อฉันได้รับคำตอบจากเซิร์ฟเวอร์ของฉัน) สามารถเข้าถึงคำขอ / แบทช์ / แบทช์เฉพาะและเรียกใช้ฟังก์ชันใดก็ได้ที่ต้องการ
ฉันไม่สามารถสร้าง vars ในชั้นเรียนของฉันโดยใช้ประเภทใดก็ได้จาก JSONRPCKit
ฉันได้รับข้อผิดพลาดของคอมไพเลอร์ตามบรรทัดของ:
โปรโตคอล 'Batch' สามารถใช้เป็นข้อ จำกัด ทั่วไปเท่านั้นเนื่องจากมีข้อกำหนดในตัวเองหรือประเภทที่เกี่ยวข้อง
การอ้างอิงถึงประเภททั่วไป 'Batch1' ต้องการอาร์กิวเมนต์ใน <... >
ค่าของโปรโตคอลประเภท 'Request' ไม่สามารถสอดคล้องกับ 'Request'; มีเพียงประเภท struct / enum / class เท่านั้นที่สามารถเป็นไปตามโปรโตคอลได้
ฉันลองใช้ฟังก์ชันทั่วไปในฟังก์ชันเพื่อหลีกเลี่ยงปัญหาของฉัน แต่ก็ไม่ได้ช่วยเช่นกัน
func store_b<Batch: JSONRPCKit.Batch>(_ batch: Batch){
ข้อมูลเพิ่มเติม: batch
เป็นประเภทBatch1
ดังนี้:
public struct Batch1<Request: JSONRPCKit.Request>: Batch {
และBatch
เป็นโปรโตคอล
public protocol Batch {
มีวิธีง่ายๆในการติดตามbatch
คำขอของฉันและรับคำตอบ / ฉันจะใช้ยาชื่อสามัญเหล่านี้อย่างถูกต้องได้อย่างไร
คำตอบ
แยกลายเซ็นวิธีการสร้างและประเภท 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
เป็นฟังก์ชันทั่วไปที่รับพารามิเตอร์ประเภทใดประเภทหนึ่ง ข้อ จำกัดระบุว่าประเภทของพารามิเตอร์จะต้องสอดคล้องกับโปรโตคอล<Request: JSONRPCKit.Request>
JSONRPCKit.Request
Batch1
เป็น struct ทั่วไปที่ตอบสนองความต้องการที่จะกำหนดสองประเภทภายในซึ่งทั้งสองมีความเกี่ยวข้องกับบางประเภทโดยพลการ อีกครั้งระบุว่าประเภทโดยพลการจะต้องสอดคล้องกับโปรโตคอล<Request: JSONRPCKit.Request>
JSONRPCKit.Request
ประเภทการส่งคืนจะBatch1<Request>
เชื่อมโยงทั้งสอง generics เข้าด้วยกันโดยกล่าวว่าประเภทที่ใช้สำหรับโครงสร้างที่ส่งคืนBatch1
จะตรงกับประเภทของrequest
พารามิเตอร์
เมื่อคุณเรียกใช้เมธอด create คุณต้องกรอกประเภททั่วไปด้วยชนิดคอนกรีตดังในตัวอย่าง
let batch = batchFactory.create(Subtract(minuend: 42, subtrahend: 23))
ตอนนี้คอมไพเลอร์สามารถอ่านคำจำกัดความทั้งหมดและสร้างการใช้งานที่เป็นรูปธรรมสำหรับประเภทนั้น:
public func create(_ request: Subtract) -> Batch1<Subtract>
public struct Batch1<Subtract>: Batch {
public typealias Responses = Int
public typealias Results = Result<Int, JSONRPCError>
}
นี้จะใช้ความจริงที่ว่ากำหนดSubtract
typealias Response = Int
โปรดทราบว่าไม่มีอะไรทั่วไปอีกต่อไป สิ่งเหล่านี้เป็นประเภทคอนกรีตทั้งหมด คุณจะมีปัญหาใด ๆ Batch1<Subtract>
กับการพยายามที่จะเก็บทรัพย์สินของชนิด
นี่คือเหตุผลที่คุณไม่สามารถจัดเก็บแบทช์ในคุณสมบัติได้อย่างง่ายดาย: Swift ไม่รู้ว่าจะใส่ประเภทใดลงไป!
วิธีหนึ่งในการแก้ปัญหานี้คือแทนที่จะเก็บการปิดซึ่งสามารถห่อแบทช์ทั่วไปที่ชั้นเรียนไม่จำเป็นต้องรู้
// 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)
วิธีนี้ใช้การปิดเฉพาะที่ตรงกับประเภททั่วไปและปิดด้วยการปิดที่ไม่ขึ้นอยู่กับแบบทั่วไปอีกต่อไป วิธีนี้ทุกชุดสามารถแชร์คุณสมบัติการปิดเดียวกันได้