self
may be used in a class method as a polymorphic Class instance.
therefore, the class method new
can be implemented like this:
+ (id)new
{
return [[self alloc] init];
}
and would return the correct type for the Class instance that is messaged:
ex a:
NSArray * a = [NSArray new]; // << a is an NSArray
ex b:
NSMutableArray * a = [NSMutableArray new]; // << a is an NSMutableArray
see note below.
So what you are really faced with is ensuring there are only instance methods in the protocol, and that (Class) self's methods map out to adopt the instance methods in the protocol.
As far as the design... well, let's just say I would not have written it this way. A singleton would have been clearer and more correct, but I don't even like singletons so I would not have taken that route.
The warning is produced because the Class instance (what is passed) does adopt the @protocol
specified by the delegate
parameter. The Class
instance is not an instance of the class. A protocol declaration really applies to instances of the class. For example, if you adopt NSLocking
, does the compiler expect you to also implement class methods for every instance method declared in the protocol? Answer: Never. The implementation you're dealing with is IMO one of those cases where it's a misuse of the language, but it happens to work.
To clarify the terminology:
The "Class
instance" is self
in a class method:
+ (void)foo { self; }
An "instance of the class" is self
in an instance method:
- (void)foo { self; }
In practice, -[NSObject conformsToProtocol:]
is +[NSObject conformsToProtocol:]
and +[NSObject class]
just returns self
so there are no errors at execution.
I'm still not clear, then, why I am receiving a warning, if the code meets the criteria you described.
The criteria I described applies to the execution, but it deviates from the semantics of the language -- thus, the compiler is absolutely correct on this.
For a resolution to the problem: There's no way to tell the compiler "My Class instance conforms to protocol" because declaration of adoption applies to instances of the class.
You have two primary options:
The clean, correct approach: Use an instance of the class and implement the protocol as defined.
or Typecast the class instance to the protocol:
id delegate = (id)self;
fbSession = [FBSession sessionForApplication:SHKFacebookKey
getSessionProxy:SHKFacebookSessionProxyURL
delegate:delegate];
If you choose #2, it may help to define the instance methods of the protocol to use class methods, like so:
+ (void)protocolMethod { /* do stuff */ }
- (void)protocolMethod { [self.class protocolMethod]; }
that would also imply you never need instances. It would help because it will add warnings if the protocol will change. These warnings would bubble up to class methods when you follow the convention.
To reduce noise, you may also consider creating some method to reduce the typecast to one location:
+ (id<SomeProtocol>)sharedSomeProtocolDelegate
{
return (id<SomeProtocol>)self;
}
- (id<SomeProtocol>)sharedSomeProtocolDelegate
{
return [[self class] sharedSomeProtocolDelegate];
}
then you can just write:
fbSession = [FBSession sessionForApplication:SHKFacebookKey
getSessionProxy:SHKFacebookSessionProxyURL
delegate:[self sharedSomeProtocolDelegate]];
(note that the implementations of these types are actually class clusters, and you will see something different in the debugger or if printed)