简体   繁体   English

Swift Keypath 泛型和子类化

[英]Swift Keypath Generic and Subclassing

I'm working on a class where a superclass and its subclasses have varying properties, but all of the same type that need identical processing before being assigned.我正在研究一个超类及其子类具有不同属性的类,但所有相同的类型在分配之前都需要相同的处理。 I've come up with a quite contrived and simplified example of what I'm trying to do with key paths, possibly using generics, including a non optimal, yet working variation.我想出了一个非常人为和简化的例子,说明我试图对关键路径做些什么,可能使用泛型,包括非最佳但有效的变体。

class OriginalClass {
    // this will only allow for properties that exist available on the base `OriginalClass` (and that makes sense)
    func updateAProperty(to value: Int, keyPath: ReferenceWritableKeyPath<OriginalClass, Int>) {
        // lots of custom, but common logic
        self[keyPath: keyPath] = value
    }

    // this *works*, but I don't like the cast I have to do on the first line, and the call site requires explicit
    // keypaths (including the type)
    func updateAPropertyTwo<GenClass>(to value: Int, keyPath: ReferenceWritableKeyPath<GenClass, Int>) {
        guard let self = self as? GenClass else { return }
        self[keyPath: keyPath] = value
    }

    // ideally, i want to do something like this. Basically, the compiler should (aka i WANT it to) be able to tell that
    // im working off a subclass of OriginalClass and provide the keypaths available to the subclass in addition to those
    // on the base, superclass.
//  func idealNonworking(to value: Int, keyPath: ReferenceWritableKeyPath<*AutomaticallyReplacedWithWhateverSubclass*, Int>) {
//      // lots of custom, but common logic
//      self[keyPath: keyPath] = value
//  }

    // this complains that `Same-type requirement makes generic parameter 'GenClass' non-generic`, but afaik, if it DID
    // work it SHOULD include the subclass properties (but it doesn't, to be clear)
//  func alternativeIdealYetNonworking<GenClass>(to value: Int, keyPath: ReferenceWritableKeyPath<GenClass, Int>) where GenClass == Self {
//      // lots of custom, but common logic
//      self[keyPath: keyPath] = value
//  }
}


class SecondClass: OriginalClass {
    var subclassValue = 0

    func nonWorkingExample() {
//      updateAProperty(to: subclassValue + 1, keyPath: \.subclassValue)
    }

    func subOptimalWorkingExample() {
        updateAPropertyTwo(to: subclassValue + 1, keyPath: \SecondClass.subclassValue)
//      updateAPropertyTwo(to: subclassValue + 1, keyPath: \Self.subclassValue) // runs into a runtime demangling error
//      updateAPropertyTwo(to: subclassValue + 1, keyPath: \.subclassValue)
    }

//  func optimalYetNonworkingExample() {
//      idealNonworking(to subclassValue + 1, keyPath: \.subclassValue)
//  }
}

let test = SecondClass()
print(test.subclassValue)
test.subOptimalWorkingExample()
print(test.subclassValue)

Now, I know WHY the first one won't work (the key path type is defined by the properties available on OriginalClass ), but I'm not sure why the last one wouldn't work.现在,我知道为什么第一个不起作用(关键路径类型由OriginalClass可用属性定义),但我不确定为什么最后一个不起作用。 Of course, that's less important than if someone knows how to do this当然,这比是否有人知道如何做到这一点更重要

Self is allowed in protocol extensions, so I wrote just that: Self在协议扩展中允许的,所以我只写了:

protocol P {
    // put whatever methods and properties from OriginalClass the "lots of custom,
    // but common logic" need here...
}
class OriginalClass : P {}

extension P {
    func updateAProperty(to value: Int, keyPath: ReferenceWritableKeyPath<Self, Int>) {
      // lots of custom, but common logic
        self[keyPath: keyPath] = value
    }
}

And usage:和用法:

class SecondClass: OriginalClass {
    var subclassValue = 0

    func workingExample() {
      updateAProperty(to: subclassValue + 1, keyPath: \.subclassValue)
    }
}

let test = SecondClass()
print(test.subclassValue)
test.workingExample()
print(test.subclassValue)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM