【问题标题】:Can't override function with generic parameter不能用泛型参数覆盖函数
【发布时间】:2016-07-20 20:09:16
【问题描述】:

上下文:

我有 A 类,它是 B 类的超类。A 类还具有在类声明中声明的泛型类型,它们被它的子类覆盖。

A 类有一个方法,该方法需要一个不属于类声明一部分的泛型参数。

B 类通过从类定义中指定泛型类型来覆盖类定义,并希望覆盖泛型函数。

例子:

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

    }
}

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

    }
}

问题:

B 类无法覆盖该方法,编译器错误“方法未覆盖其超类中的任何方法”

问题:

1) 首先为什么会发生这种情况?

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

        }
    }
}

【问题讨论】:

  • 如此处所示,代码没有意义。您的问题缺少一些信息 JSONModel 是什么?还有哪些其他类型符合或继承自JSONModelT 的目的是什么?它没有作为函数参数传递,那么它是如何使用的呢?
  • 示例是为了说明问题。如果它们遵循示例中的逻辑,您可以替换任何您想要的类。在“那里”的某个地方,类型 T 由调用此通用函数的其他函数确定。 T 是通用的,因为它有大约 3 种不同的类型,根据被调用函数,它将被“转换”为。无论如何,从 JSONModel 继承的其他类型或调用此函数的其他函数与所述问题无关。

标签: swift generics overriding


【解决方案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"

【讨论】:

  • 我只提供了我的代码的最简单表示。在实践中,我需要专门具有类型 T 才能将其序列化为正确的实例。示例中未显示的函数使用此通用函数并传入特定类型,从而确定如何序列化实例。无论如何,这是一个很长的故事。我的想法是我需要上面指定的代码,我正在寻找通过不添加其他协议/类来解决这个通用冲突,因为这是一个巨大的 SDK,像这样的更改还需要一些其他“架构”更改。跨度>
  • 这仍然是一个有趣的想法,以防 smb 具有更简单代码的灵活性以及添加大量更改的能力。
  • 请澄清您的问题,以说明您如何使用T,或者为什么它被定义为函数上的泛型。
  • 我添加了更多上下文。希望对您有所帮助。
  • 同样,NSDictionary 作为泛型类型只是为了在其中放置一个类。实际上,它是其他模型类继承的基础模型类。
【解决方案2】:

您可以省略 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

【讨论】:

  • 使用我的示例中提供的代码,我刚刚使用了没有覆盖 [在 B 类中] 的方法并在那里打印。然后创建了一个 B 的实例并在其上调用了 TreatRequestResponse。没有调用 B 中的方法,而是调用了 A 中的方法。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-06-03
  • 1970-01-01
  • 2018-06-20
  • 2020-03-12
  • 1970-01-01
相关资源
最近更新 更多