17

I have the following class:

class BaseCache<T: Equatable>: NSObject {

    var allEntities = [T]()

    // MARK: - Append

    func appendEntities(newEntities: [T]) {
        ....
    }
}

Now I want to subclass it, but I get annoying error, that my type "does not conform to protocol 'Equatable'": enter image description here

It seems generics in Swift are real pain-in-the-ass.

6
  • It might be easier just to add the the protocol at the class definition. class Aftership : Equatable { } Commented Jan 5, 2015 at 5:24
  • That's impossible, because Aftership SDK is written on Objective C Commented Jan 5, 2015 at 5:25
  • Maybe put the == func inside the extension so it is actually conforming to the protocol. Commented Jan 5, 2015 at 5:59
  • == func must be global, so it must be outside of extension definition. Actually, AftershipTracking conforms to Equatable protocol, otherwise I'd get a compiler warning on extension row. Commented Jan 5, 2015 at 6:03
  • 3
    Looks like you have to skip generics altogether. I really hate some of the limitations of swift generics. Commented Jan 5, 2015 at 6:22

2 Answers 2

25

Your class definition of TrackingCache is wrong. It repeats the generic parameter:

class TrackingCache<AftershipTracking>: BaseCache<AftershipTracking> { }

It should be left out:

class TrackingCache: BaseCache<AftershipTracking> { }

This triggers the underlying swift error Classes derived from generic classes must also be generic. You can work around this issue by specifying a type parameter that is required to be or inherit from AftershipTracking:

class TrackingCache<T: AftershipTracking>: BaseCache<AftershipTracking> { }

Full example:

class BaseCache<T: Equatable>: NSObject {
  var items: [T] = []

  func appendItems( items: [T]) {
    self.items += items
    didAppendItems()
  }

  func didAppendItems() {} // for overriding
}

class AftershipTracking: NSObject {
  var identifier: Int
  init( identifier: Int) {
    self.identifier = identifier
    super.init()
  }
}

extension AftershipTracking: Equatable { }

func ==( lhs: AftershipTracking, rhs: AftershipTracking) -> Bool {
  return lhs.identifier == rhs.identifier
}

class TrackingCache<T: AftershipTracking>: BaseCache<AftershipTracking> {
  override func didAppendItems() {
    // do something
  }
}

let a = TrackingCache<AftershipTracking>()
let b = TrackingCache<AftershipTracking>()

a.appendItems( [AftershipTracking( identifier: 1)])
b.appendItems( [AftershipTracking( identifier: 1)])

let result = a.items == b.items // true
Sign up to request clarification or add additional context in comments.

6 Comments

Thanks for the answer, but I tried that already and it didn't work. If I define my class as class TrackingCache<T: AftershipTracking>: BaseCache<AftershipTracking>, I get an error "Method does not override any method from it's superclass" on each override func row.
Yes, but that's another issue. Your BaseCache class derives from something else than NSObject right? As soon as you derive a generic class from an Objective-C class, the derived swift class can't see the super-methods anymore. You can work around this by introducing an intermediate non-generic subclass in swift. But this is really a separate issue. My answer is the correct solution to your question.
BaseCache derives directly from NSObject, as stated above. Even if I remove NSObject, that doesn't change anything
If a method that you try to override has a generic type in its parameter list it will be a different method: appendItems( items: [Equatable]) is different from appendItems( items: [AftershipTracking]). You can still call the supermethod though. I'll update the example.
Thanks, this fixes the previous issue, but gives another one. When I try to call appendEntities method, I get an error: Ambiguous use of 'appendEntities'. I can't understand why compiler thinks that AfterTracking and T are a different types - that's the problem
|
9

this should work: < swift 4 >

class TrackingCache<T: AftershipTracking>: BaseCache<T>

Another example:

protocol P {

}

class C: P {

}

class CS: C {

}

class L<T:P> {
    let c: T

    init(_ c: T) {
        self.c = c
    }
}

class LS<T:CS>:L<T> {

}

let i = LS(CS())

i.c

c is CS now.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.