Swift : 일반 유형의 인스턴스를 클래스 변수에 할당 하시겠습니까?
나는 이것을 사용하려고 https://github.com/bricklife/JSONRPCKit. Swift 용 JSONRPC의 간단한 구현입니다.
이것은 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
클래스의 함수에서 생성 된 경우에도를 추적하고 싶습니다 . 그래서 다른 기능 (내 서버에서 응답을받을 때). 특정 요청 / 배치 / 배치 요소에 액세스하고 필요한 모든 기능을 실행할 수 있습니다.
JSONRPCKit의 유형을 사용하여 내 클래스에서 변수를 만들 수 없습니다.
다음 줄을 따라 컴파일러 오류가 발생합니다.
프로토콜 'Batch'는 자체 또는 관련 유형 요구 사항이 있으므로 일반 제약으로 만 사용할 수 있습니다.
제네릭 유형 'Batch1'에 대한 참조에는 <...>에 인수가 필요합니다.
프로토콜 유형 'Request'의 값은 'Request'를 준수 할 수 없습니다. struct / enum / class 유형 만 프로토콜을 준수 할 수 있습니다.
어떻게 든 내 문제를 피하기 위해 제네릭 함수를 사용하려고 시도했지만 도움이되지 않았습니다.
func store_b<Batch: JSONRPCKit.Batch>(_ batch: Batch){
더 많은 정보 : batch
is of type Batch1
, like so :
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
두 가지 내부 유형을 정의해야하는 일반 구조체입니다. 둘 다 임의 유형 과 연결되어 있습니다 . 다시 말하지만, <Request: JSONRPCKit.Request>
임의의 유형이 프로토콜을 준수해야 함을 지정합니다 JSONRPCKit.Request
.
반환 유형 Batch1<Request>
은이 두 제네릭을 함께 묶어 반환 된 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)
이 메서드는 제네릭 유형과 일치하는 특정 클로저를 가져와 더 이상 제네릭에 종속되지 않는 클로저로 래핑합니다. 이렇게하면 모든 배치가 동일한 클로저 속성을 공유 할 수 있습니다.