简体   繁体   中英

Swift Class Pointer as? Class Protocol?

I have a class, lets call it SomeClass. Instances of SomeClass have an optional pointer to SomeOtherClass. In this way, instances of SomeClass can be instantiated, given a pointer to SomeOtherClass (or a subclass of SomeOtherClass), and then this pointer can be used to dynamically create instances of this SomeOtherClass belonging to SomeClass. Eg;

class SomeClass {
    var classPointer: SomeOtherClass.Type?
}

class SomeOtherClass {
}

So far so good. Now, I have a protocol - lets call it SomeProtocol - that I want SomeOtherClass to conform to. This protocol has class functions in it:

protocol SomeProtocol {
    static func someClassFunction()
}

extension SomeOtherClass : SomeProtocol {
    class func someClassFunction() {
        print("I am a class function being executed on SomeOtherClass")
    }
}

As expected, I can then call this protocol class function on SomeOtherClass like so:

SomeOtherClass.someClassFunction() // Prints "I am a class function being executed on SomeOtherClass"

Here is the troublesome part. I want to dynamically determine if an instance of SomeClass' classPointer conforms to SomeProtocol, and if so execute the class function on it. So, I try to cast the pointer using as?:

// Create an instance of SomeClass and set it's classPointer to the SomeOtherClass class
let someInstance = SomeClass()
someInstance.classPointer = SomeOtherClass.self

// Check if the instance's classPointer class conforms to the SomeProtocol protocol
if let conformingClass = someInstance.classPointer as? SomeProtocol {
    // If so, execute the class function in SomeProtocol on the instance's classPointer
    conformingClass.someClassFunction() // Build fails "Static member someClassFunction cannot be used on instance of type SomeProtocol"
}

And the build fails with the error "Static member of someClassFunction cannot be used on instance of type SomeProtocol".

Is there a way to accomplish what I'm attempting? Currently if this doesn't work I can only think of these alternatives (none are preferable and they're all rather hacky):

  1. Switch to objective c.
  2. Switch the protocol to use instance functions instead, then instantiate a temporary instance of SomeClass' classPointer and message it with any necessary functions, then release the instance.

For completeness, here is all of the code together that can be pasted into a Playground (it won't build due to the error I mentioned though):

class SomeClass {
    var classPointer: SomeOtherClass.Type?
}

class SomeOtherClass {
}

protocol SomeProtocol {
    static func someClassFunction()
}

extension SomeOtherClass : SomeProtocol {
    class func someClassFunction() {
        print("I am a class function being executed on SomeOtherClass")
    }
}

// Create an instance of SomeClass and set it's classPointer to the SomeOtherClass class
let someInstance = SomeClass()
someInstance.classPointer = SomeOtherClass.self

// Check if the instance's classPointer class conforms to the SomeProtocol protocol
if let conformingClass = someInstance.classPointer as? SomeProtocol {
    // If so, execute the class function in SomeProtocol on the instance's classPointer
    conformingClass.someClassFunction() // Build fails "Static member someClassFunction cannot be used on instance of type SomeProtocol"
}

Thanks for any help you can provide, - Adam

Ahah! As usual, as soon as I make the SO post, I figure out the answer.

For those wondering, you must cast the classPointer as the protocol's Type, not as the protocol itself. The line:

if let conformingClass = someInstance.classPointer as? SomeProtocol {

Needs to be changed to:

if let conformingClass = someInstance.classPointer as? SomeProtocol.Type {

And you'll then be able to message conformingClass with the class functions declared in SomeProtocol. The complete working code is:

class SomeClass {
    var classPointer: SomeOtherClass.Type?
}

class SomeOtherClass {
}

protocol SomeProtocol {
    static func someClassFunction()
}

extension SomeOtherClass : SomeProtocol {
    class func someClassFunction() {
        print("I am a class function being executed on SomeOtherClass")
    }
}

// Create an instance of SomeClass and set it's classPointer to the SomeOtherClass class
let someInstance = SomeClass()
someInstance.classPointer = SomeOtherClass.self

// Check if the instance's classPointer class conforms to the SomeProtocol protocol
if let conformingClass = someInstance.classPointer as? SomeProtocol.Type {
    // If so, execute the class function in SomeProtocol on the instance's classPointer
    conformingClass.someClassFunction()
}

And it works :).

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