Home > OS >  How to define a `Class` object type conforming to a protocol?
How to define a `Class` object type conforming to a protocol?

Time:01-19

Consider the following Objective-C protocol declaration, which requires only class methods:

@protocol TDWMethoding<NSObject>

  (void)foo;
  (void)bar;

@end

Assuming I need to return an instance of a Class which conforms to this protocol from a method, how am I supposed to specify the return type?

- (nullable /*return-type*/)instantiateMethoding {
    Class instance = ... // some implementation
    if ([instance conformsToProtocol:@protocol(TDWMethoding)]) {
        return instance;
    }
    return nil;
}

There are a number of working options I considered so far in regards to how to express the /*return-type*/, but each has its own downsides:

  1. Class - this way it doesn't expose conformance. What kind of Class is it? What does it do? Does it conform to the protocol at all?
  2. Class<TDWMethoding> - this looks like a viable solution and even was suggested a few times by other developers (here and here) but I personally find it inconsistent and misleading: when we have a variable of form Type<Protocol> *instance, it commonly means that protocol class methods should be sent to the instance's class ([[instance class] foo]) not the instance itself ([instance foo]);
  3. id<TDWMethoding> and returning an instance of the class instead - this is consistent, but it requires me to instantiate the class, which is both redundant and prevents me from hiding the constructors of the utility classes which conforms to the protocol with NS_UNAVAILABLE macro.

Is there a better semantic to express such a return-type?

CodePudding user response:

Class<TDWMethoding> is correct. It's not inconsistent. When something is of type Class, you send class methods to it. When something is an instance, and you want to send to the class, you access its -class.

That said, this does seem very strange, and likely means you're overusing Class methods. You should think hard about whether a sharedInstance is a better model for this.

But if you want to identify the type, Class<TDWMethoding> is correct, though id would likely be more common, as discussed in How to cast Class object to conformance witih protocol.

CodePudding user response:

After digging a little deeper into The Objective-C Programming Language documentation, I actually found the exact answer to such a scenario:

Protocols can’t be used to type class objects. Only instances can be statically typed to a protocol, just as only instances can be statically typed to a class. (However, at runtime, both classes and instances respond to a conformsToProtocol: message.)

Which means that it's just not supported and I should implement this differently. (e.g. with use of a singleton pattern, as suggested in Rob's answer)

  • Related