Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
1.1k views
in Technique[技术] by (71.8m points)

swift - Protocol for class method

I want to declare in a protocol a class func, I intend to conform to this protocol from a class A, B and C.

B and C inherit from A.

Essentially I want to override this func in B and C while still providing an implementation in A.

So, I had to declare my protocol as follows:

protocol MyManagedObjectCoolStuff {

    static func entityName() -> String
}

And then I have this in A:

class A: NSManagedObject { }

class B: A { }

class C: A { }

extension A: MyManagedObjectCoolStuff {

  static func entityName() -> String {
        return "Animal"
    }
}

extension B: MyManagedObjectCoolStuff {

   override static func entityName() -> String {
        return "Bat"
    }
}

extension C: MyManagedObjectCoolStuff {

   override static func entityName() -> String {
        return "Cat"
    }
}

The problem here, is clear and Xcode confirms: "Class method overrides a 'final' class method".

enter image description here

How can I work around this? I cannot use class func in the protocol... I'm not sure how to abstract this.

Thanks!

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

In a class definition, static is an alias for class final, so it marks a type method (or property) which cannot be overridden in subclasses.

Since you want to override the method in subclasses, all you have to do is to define the method as class instead of static:

extension A: MyManagedObjectCoolStuff {

    class func entityName() -> String {
        return "Animal"
    }
}

extension B: MyManagedObjectCoolStuff {

    override class func entityName() -> String {
        return "Bat"
    }
}

extension C: MyManagedObjectCoolStuff {

    override class func entityName() -> String {
        return "Cat"
    }
}

Alternatively one could use the fact that for a Core Data entity, the class name is usually defined as <ModuleName>.<EntityName> so that the entity name is the last component of the class name.

So you could define entityName() as an extension method of NSManagedObject (the superclass of all Core Data object classes) as in How can I create instances of managed object subclasses in a NSManagedObject Swift extension?:

extension NSManagedObject {

    class func entityName() -> String {
        let classString = NSStringFromClass(self)
        // The entity is the last component of dot-separated class name:
        let components = split(classString) { $0 == "." }
        return components.last ?? classString
    }
}

and override it only where necessary:

class A: NSManagedObject { }

class B: A { }

class C: A { }

extension C {

    override class func entityName() -> String {
        return "Cat"
    }
}

println(A.entityName()) // A
println(B.entityName()) // B
println(C.entityName()) // Cat

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...