Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Adding category method to NSObject, but getting warnings because it's not in the <NSObject> protocol when I call it

(I found some questions discussing the idea, but I didn't see a solution for my problem.)

I added this convenience method as a category to NSObject. (I've added other methods, so I'm still interested in an answer even if you disagree with this particular convenience method.)

@implementation NSObject (MyCategory)
- (void)performInvocationOnMainThread:(NSInvocation *)invocation waitUntilDone:(BOOL)waitForMainThread;
@end

Then I have a protocol I defined:

@protocol MyDelegateProtocol <NSObject>
- (void)myDelegateProtocolMethod;
@end

Then I declare the delegate as a property of my class that implements said protocol.

@property (nonatomic, assign) id <MyDelegateProtocol> delegate;

But when I try to call the NSObject method I added in my category like so

NSInvocation *invocation = [self.delegate invocationForSelector:@selector(someSelector:withArg:)];

I get this warning

'-performInvocationOnMainThread:waitUntilDone:' not found in protocol(s)

If I cast my delegate as (NSObject *) then I don't get the warning. What am I doing wrong? It didn't seem like I could (or should?) add methods to an existing protocol without creating a "sub protocol" and using it from then on. (Which kind of defeats the point of adding methods to NSObject in mind.)

NSInvocation *invocation = [(NSObject *)self.delegate invocationForSelector:@selector(someSelector:withArg:)];
like image 299
zekel Avatar asked Feb 24 '23 04:02

zekel


2 Answers

Your category extends the NSObject class, not the NSObject protocol. While the class now has the method, it's not defined as part of the protocol, hence the warning.

That's why typecasting to the NSObject * pointer type works; you're casting to the NSObject class type, rather than something like id<NSObject> which means an arbitrary Objective-C object that conforms to the NSObject protocol.

You'll have to make an intermediate protocol (or "sub protocol") that extends the NSObject protocol:

@protocol ExtendedNSObject <NSObject>
- (void)performInvocationOnMainThread:(NSInvocation *)invocation waitUntilDone:(BOOL)waitForMainThread;
@end

Then have your delegate protocol extend that one instead:

@protocol MyDelegateProtocol <ExtendedNSObject>
- (void)myDelegateProtocolMethod;
@end

If I'm not wrong, you can keep the existing NSObject (MyCategory) implementation, and they'll play nice together.

like image 120
BoltClock Avatar answered Feb 26 '23 17:02

BoltClock


when pass/expect this type, qualify it like so:

- (void)race:(NSObject<MyDelegateProtocol>*)arg;
like image 42
justin Avatar answered Feb 26 '23 16:02

justin