Search code examples
objective-cobjective-c-category

How do I define a category that adds methods to classes which implement a particular protocol?


I want to add some methods to subclasses of NSManagedObject that implement the SOManagedObject protocol. I've tried defining it like this:

@interface NSManagedObject <SOManagedObject> (MyExtensionMethods)
    ...
@end

...but that doesn't seem to be valid. How do I define a category that adds methods to classes which implement a particular protocol?


Solution

  • Defining such a category on all such classes in general is not easily solvable. But your actual problem seems simpler: How does one add a category method to NSManagedObject for use only with subclasses that implement <SOManagedObject>? This is solvable.

    What you want to do is add the method to NSManagedObject, then check that the instance you're working with can handle the messages you want to send it from <SOManagedObject>.

    Let us suppose that we are given:

    /* SOManagedObject.h */
    @protocol SOManagedObject
    - (void)frobble_so;
    - (void)bobble_so;
    @end
    

    Now let's add a category method to all NSManagedObject subclasses that implement SOManagedObject:

    /* NSManagedObject+SOConvenience.h */
    @interface NSManagedObject (SOConvience)
    /* Frobbles and bobbles - no effect on non-<SOManagedObject>-conforming
     * instances. */
    - (void)frobbleAndBobble_so;
    @end
    

    To do so, we implement the method like so:

    /* NSManagedObject+SOConvenience.m */
    @implementation NSManagedObject (SOConvenience)
    - (void)frobbleAndBobble_so
    {
        if (![self conformsToProtocol:@protocol(SOManagedObject)]) return;
    
        NSLog(@"%s: Thunderbirds are GO! Let's frobble and bobble!", __func__);
        [self frobble_so];
        [self bobble_so];
    }
    @end
    

    You could optionally assert to ensure you are not sending the method to the wrong objects, or you could use respondsToSelector: instead of checking for protocol conformance. Whatever floats your boat, but this general tack should take you where you want to go.