2016-07-20 3 views
2

컨텍스트 함수를 재정의 할 수 없습니다제네릭 매개 변수

나는 또한 아이 클래스의에 의해 오버라이드 (override)하는 클래스 선언에서 선언 일반적인 종류가 클래스 B를 A 급의 슈퍼 클래스입니다 클래스 A가 있습니다.

클래스 A에는 클래스 선언의 일부가 아닌 일반 매개 변수가 필요한 메서드가 있습니다.

클래스 B는 클래스 정의에서 제네릭 형식을 지정하여 클래스 정의를 재정의하고 제네릭 함수를 재정의하려고합니다.

예 :

문제
class A<U: NSDictionary, Z: NSDictionary> : NSObject 
{ 
    func funcToOverride<T : JSONModel>() 
    { 

    } 
} 

class B : A<NSDictionary, NSDictionary> 
{ 
    override func funcToOverride<T:JSONModel>() 
    { 

    } 
} 

:

1 : 컴파일러 에러 메소드를 무시할 수 없다

클래스 B가

질문 "방법이 수퍼으로부터 임의의 방법을 대체하지 않는다") 왜 이것이 처음부터 발생합니까?

2)이 문제를 피하는 알려진 방법이 있습니까? 내 수퍼 클래스는 B 이외의 다른 하위 클래스에 대해서도 수퍼 클래스이므로 클래스 정의에 일반 매개 변수를 추가하면 단일 함수의 형식을 정의하는 데 문제가 있습니다.

추가 참고 사항 :

이 코드는 엄격히 적용됩니다. 기존의 큰 SDK 내부에서 작업하는 훨씬 복잡한 코드의 샘플. 필자는 현재 컨텍스트와 관련이없는 프로토콜이나 다른 클래스를 추가하지 않으므로 제네릭 충돌 문제를 해결해야합니다.

경우 누군가의 요청으로

더 큰 컨텍스트에 대한 필요성을 느낀다

더 확장 된 샘플 버전 : 코드 있지만

class A<ResponseModel : NSDictionary, RedirectModel : NSDictionary>: NSObject { 

    let existingCompletionHandler : (responseModel : ResponseModel?, error : NSError?) -> Void = { 
     (responseModel : ResponseModel?, error : NSError?) -> Void in 
    } 

    func presentWebViewAndWaitForRedirect(redirectQueryPath : String) 
    { 
     let queryPathToDict : [NSObject : AnyObject] = [:] 

     treatRedirectWithResponseParams(queryPathToDict) {[weak self] (model, error) in 
      self?.callSomeRandomRequestWithRedirectModel(model) 
     } 
    } 

    func callSomeRandomRequestWithRedirectModel(redirectModel : RedirectModel?) 
    { 
     let requestResult : [NSObject : AnyObject] = [:] 

     treatRequestResponse(requestResult, completionHandler: existingCompletionHandler) 
    } 

    func treatRedirectWithResponseParams(responseParams : [NSObject : AnyObject], completionHandler : (model : RedirectModel?, error : NSError?) -> Void) 
    { 
     funcToOverride(responseParams, completionHandler: completionHandler) 
    } 

    func treatRequestResponse(someRequestResult : [NSObject : AnyObject], completionHandler : (model : ResponseModel?, error : NSError?) -> Void) 
    { 
     funcToOverride(someRequestResult, completionHandler: completionHandler) 
    } 

    func funcToOverride<T : NSDictionary>(params : [NSObject : AnyObject], completionHandler : (model : T?, error : NSError?) -> Void) 
    { 

    } 
} 


class B: A<NSDictionary, NSDictionary> { 

     //wants to provide something additional or different to the base implementation but still respect the base class logic flow 
     override func funcToOverride<T : NSDictionary>(params: [NSObject : AnyObject], completionHandler: (model: T?, error: NSError?) -> Void) { 

     } 
    } 

class SomeOtherRandomClass : NSDictionary 
{ 

} 

class C: A<NSDictionary, NSDictionary> { 

    func someOtherClassCRequest() 
    { 
     let response : [NSObject : AnyObject] = [:] 

     funcToOverride(response) { (model : SomeOtherRandomClass?, error : NSError?) in 

     } 
    } 
} 
+0

은 여기에 나타낸 바와 같이, 코드는 거의 의미가 있습니다. 귀하의 질문에 일부 정보가 없습니다.'JSONModel '이란 무엇입니까? 'JSONModel'을 따르거나 상속 한 다른 유형은 무엇입니까? 'T'의 목적은 무엇입니까? 함수 매개 변수로 전달되지 않으므로 어떻게 사용됩니까? –

+0

샘플에서는 문제를 보여줍니다. 샘플의 논리를 따르는 경우 원하는 모든 클래스를 바꿀 수 있습니다. 어딘가에 "유형"이 T를이 일반 함수를 호출하는 다른 함수에 의해 결정됩니다. 또한 T는 호출 수신 기능에 따라 "변환"되는 약 3 가지 유형이 있기 때문에 일반적입니다. 어쨌든이 함수를 호출하는 JSONModel 또는 다른 함수를 상속하는 다른 유형은 명시된 문제와 관련이 없습니다. – Fawkes

답변

1

, 당신이 실제로 어딘가에 타입 T를 사용하는 가정 예는 이것을 보여주지 않습니다.

제네릭을 사용할 필요가 없습니다.

입력 유형 T는 항상 JSONModel로 정의되므로이 함수는 JSONModel에 정의 된 것을 제외하고는 추가 속성이나 메소드에 액세스 할 수 없습니다. 참조하는 모든 유형이 JSONModel을 준수해야합니다 (상속 또는 프로토콜을 통해). JSONModel을 사용할 수도 있습니다.

유일한 다른 사용 사례는 JSONModel 인스턴스의 특정 멤버에 액세스해야한다는 것입니다.이 경우 함수 오버로드를 사용할 수 있습니다.

예 :

protocol JSONModel { 
    func hello() -> String 
} 

class ModelA: JSONModel { 
    func hello() -> String { 
     return "Hello Model A" 
    } 
} 

class ModelB: JSONModel { 
    func hello() -> String { 
     return "Hello Model B" 
    } 

    func goodbye() -> String { 
     return "Goodbye Model B" 
    } 
} 

class A<U: NSDictionary, Z: NSDictionary>: NSObject 
{ 
    func fromJSON(t: JSONModel) 
    { 
     print("From A: \(t.hello())") 
    } 
} 

class B : A<NSDictionary, NSDictionary> 
{ 
    override func fromJSON(t: JSONModel) 
    { 
     print("From B: \(t.hello())") 
    } 

    func fromJSON(t: ModelB) 
    { 
     print("From B: \(t.goodbye())") 
    } 
} 

let a = A() 
a.fromJSON(ModelA()) // "From A: Hello A" 

let b = B() 
b.fromJSON(ModelB() as JSONModel) // "From B: Hello B" 
b.fromJSON(ModelB()) // "From B: Goodbye B" 
+0

나는 내 코드를 가장 단순하게 표현했다. 실제로 나는 그것을 올바른 인스턴스로 직렬화하기 위해 특별히 T 타입을 가질 필요가 있습니다. 샘플에서 보여되지 않은 기능이 일반적인 함수를 사용하고, 따라서 예를 직렬화하는 방법을 결정하고, 특정한 형태로 전달한다. 어쨌든 그것은 긴 이야기입니다. 아이디어는 위에서 지정한 방식으로 코드를 필요로하고 다른 프로토콜/클래스를 추가하지 않아서이 일반적인 충돌을 해결하려고합니다. 거대한 SDK이므로이 "아키텍처"변경이 필요합니다. – Fawkes

+0

아직도이 경우 SMB의 흥미로운 아이디어는 간단한 코드와 상당한 변화를 추가 할 수있는 기능의 유연성을 가지고있다. – Fawkes

+0

당신은'T'를 사용하고, 또는 왜 그것이 기능에 대한 일반적인 정의하는 방법을 보여주기 위해 질문을 명확히하십시오. –

1

당신은 단지 override 키워드를 생략 할 수 있습니다. 상속은 정상적으로 작동합니다.

import Cocoa 
import XCPlayground## Heading ## 

class JSONModel { 
    required init() { 
    } 
} 

class ModelA: JSONModel { 
    var name: String? 
    required init() { 
    } 
} 

class ModelB: JSONModel { 
    var size: Int? 
    required init() { 
    } 
} 

class A<U: NSDictionary, Z: NSDictionary>: NSObject 
{ 
    let prefix = "A" 

    func funcToOverride<T: JSONModel>(u: [String: AnyObject], c: (T?) -> Void) 
    { 
     let t = T() 
     (t as? ModelA)?.name = "From A: " + ((u["name"] as? String) ?? "-none-") 
     (t as? ModelB)?.size = u["size"] as? Int ?? 0 
     c(t) 
    } 
} 

class B : A<NSDictionary, NSDictionary> 
{ 
    let suffix = "B" 

    func funcToOverride<T: JSONModel>(u: [String: AnyObject], c: (T?) -> Void) 
    { 
     let t = T() 
     (t as? ModelA)?.name = "From B: " + ((u["name"] as? String) ?? "-none-") 

     if t is ModelB { 
      return super.funcToOverride(u, c: c) 
     } 

     c(t) 
    } 
} 

let a = A() 

a.funcToOverride(["name": "foo"]) { (m: ModelA?) in 
    print("From A: \(m) \(m?.name)") 
} 

a.funcToOverride(["size": 10]) { (m: ModelB?) in 
    print("From A: \(m) \(m?.size)") 
} 


let b = B() 

b.funcToOverride(["name": "bar"]) { (m: ModelA?) in 
    print("From B: \(m) \(m?.name)") 
} 

b.funcToOverride(["size": 10]) { (m: ModelB?) in 
    print("From B: \(m) \(m?.size)") 
} 

XCPlaygroundPage.currentPage.needsIndefiniteExecution = true 
+0

, 방금 [는 B 클래스] 재정이없는 방법을 사용하고 거기에 인쇄를 넣었습니다. 그런 다음 B 인스턴스를 작성하고 거기에 treatRequestResponse를 호출합니다. B의 메소드가 호출되지 않았고 대신 A의 메소드가 호출되었습니다. – Fawkes

관련 문제