简体   繁体   中英

Swift Inherit from Generic Type

I'm trying to inherit from a generic type, so that I can insert a type into a hierarchy:

class Foo < T:AnyObject > : T {}

but I get error

inheritance from non-protocol, non-class type 'T'

but I'm ensuring T is a class (even if I change AnyObject to some other class). Is this just not possible?

You can't inherit from something if you don't know what it is, for multiple reasons.

  • For one, the compiler needs to know how to lay out an instance of your class in memory. To do that, it needs to know what instance variables (stored properties) it has: both those the class specifies and those inherited from a superclass.

  • The compiler also needs to know about the superclass' properties and initializers to make sure that an instance of your class is properly initialized. If the superclass' properties are unknown, there's no way to know if you've initialized all the state that you should (and none that you shouldn't) before your initializer ends. If the superclass' initializers are unknown, the compiler can't enforce that you call a superclass' designated initializer from your own.

  • How will you write method implementations that reference properties and methods of the superclass if you don't know what the superclass is? If you write code that references self.view , then somehow instantiate a version of your class that doesn't inherit from a class with that property, that code would break.

There are probably several more reasons, but these should be enough. :)

Though there are a few places where you're expected to subclass, Cocoa (whether in Swift or ObjC) generally favors composition instead of inheritance for customization.

If you're adding a bunch of functionality to various view controllers, and reusing the code for such by factoring it out into its own class, the simple solution is to make your view controller classes all own an instance of that class instead of trying to be that class. If you have places where you want to enforce that certain view controller classes must own a Foo , you can define a protocol that expresses that requirement.

If you're trying to add functionality to an existing class, you can use an extension. You might not be able to use an extension to add stored properties, but you can certainly fake it. For example, you could use computed properties, and define your own storage within their implementation. One way to do that might be to use the associated objects feature of the ObjC runtime (which AFAIK is still accessible from Swift).

Isn't CRTP ( Curiously recurring template pattern ) different than in the OP anyways?

It's totally fine to design that pattern in Swift (<= 3.0), but it's currently bugged and will lock on initialization without any error during runtime.

class Template<T> { ... }

class RealThing : Template<RealThing> { ... }

I recently discovered this pattern in bridged UIKit API. You can read that in my short blog post here .

I also translated the example from wiki into Swift 3.0:

protocol Constructor {
    init()
}

protocol Shape {
    func cloned() -> Shape
}

typealias ShapeProtocols = Constructor & Shape

class Shape_CRTP<T> : ShapeProtocols {

    required init() {}

    func  cloned() -> Shape {
        let new = Shape_CRTP<T>()
        // copy everything to `new` from `self`
        return new
    }
}

extension Shape_CRTP where T : ShapeProtocols {

    func cloned() -> Shape {
        let new = T()
        // copy everything to `new` from `self`
        return new
    }
}

// First non-crtp proof of concept
class Square : ShapeProtocols {

    required init() {}
    func cloned() -> Shape {
        return Square()
    }
}

let clone = Shape_CRTP<Square>().cloned() // creates a new `Shape`
type(of: clone) // Square.Type

// now CRTP but this is bugged: http://blog.devandartist.com/posts/swift-crtp
class Circle : Shape_CRTP<Circle> {}

Circle().cloned()

print("this will never print because of the described bug")

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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