2

I'm working on a Core Data application where my entities have a common property called deleted (I'm implementing logical deletion in the app).

While all the entities could inherit from a common one, I would like to avoid it (I don't like how when using inheritance all the entities end up in the same table, but I digress).

In order to keep the code tidy, I implemented a protocol as such:

@protocol SPRLogicalDeleteEntity <NSObject>

@property (nonatomic, retain) NSNumber * deleted;

@end

and I want all the NSManagedObject subclasses to conform to this protocol, so the code looks better. In order for the code to be maintainable, I don't want to add the protocol to the generated NSManagedObject subclasses, so instead, I created a class extension:

@interface Product () < SPRLogicalDeleteEntity >

@end

that I use only to mark the entity as conforming to my protocol.

The problem I'm having is that calls to conformsToProtocol:@protocol(SPRLogicalDeleteEntity) return NO.

I haven't tried mogenerator (but I could if strictly required). Any tip? Could this be because the class extension is empty and thus not loading?

pgb
  • 24,813
  • 12
  • 83
  • 113
  • Yes, I am. The thing is that it doesn't have an accompanying implementation block, as it's only a marker. – pgb May 23 '13 at 15:02
  • Oh, I deleted my comment by mistake. Anyway, if it's a class extension then it has an implementation block. It's the one inside `Product.m`. Just make sure to include the extension header from `Product.m`. – Sulthan May 23 '13 at 15:04
  • 2
    Side note: Don't call a managed object property "deleted", or strange things may happen (compare http://stackoverflow.com/a/16003894/1187415). – Martin R May 23 '13 at 15:06
  • Perhaps you could try overriding the `conformsToProtocol:` method to return `YES` for this protocol? Or will that tear apart the fabric of spacetime? – Maarten May 23 '13 at 15:08
  • @MartinR thank's for the side note! Probably saved me tons of time in my future! – pgb May 23 '13 at 15:14
  • 1
    @Maarten I would feel dirty as hell :) – pgb May 23 '13 at 15:17
  • @pgb :] Well, perhaps that's still your best bet considering that `conformsToProtocol:` "determines conformance solely on the basis of the formal declarations in header files" [source](http://developer.apple.com/library/ios/#documentation/cocoa/reference/foundation/Classes/NSObject_Class/Reference/Reference.html#//apple_ref/occ/clm/NSObject/conformsToProtocol:) – Maarten May 23 '13 at 15:21
  • @Maarten It should still work without problems. Adopting protocols on class extensions is pretty common. I guess it's some header import mixup. Maybe cyclical dependency in headers? – Sulthan May 23 '13 at 15:43
  • @Maarten Maybe, but I could not find it. I switched to `mogenerator` that creates a subclass instead, to get back to work, but it's still puzzling me. – pgb May 23 '13 at 15:45
  • As an aside, using mogenerator is an extremely good idea even if it's not "strictly required". It's a much, much better way to deal with custom subclasses. – Tom Harrington May 23 '13 at 15:59
  • You could add a fake method to the protocol and then check in the class importing the extension, if it sees the method. Just to see what happens there. – Sulthan May 23 '13 at 16:33
  • @pgb: What exactly is your goal? Do you want to ensure that all managed object subclasses conform to the protocol at compile time? Or you want to check the conformance at runtime? – Martin R May 23 '13 at 18:10
  • I want to check the conformance at runtime, in case in the future some entity of the project does not support this feature. I switched to `mogenerator` and it's working, but I'll leave the question open in case someone comes up with a good answer. – pgb May 23 '13 at 19:01
  • 1
    @pgb: The only alternative I can think of is to create a class *category* instead of an extension: `@interface Product (MyCategory) @end` and `@implementation Product (MyCategory) @dynamic theCommonProperty; @end`. - Then "conformsToProtocol" works, but your subclass solution (using mogenerator) is perhaps more elegant. – Martin R May 23 '13 at 19:16
  • Yes. The weird thing with a category is that I ended up with the property declared twice: in the main `@implementation` block, as it's part of the `NSManagedObject` and in the category. It's `@dynamic` so it wasn't a big deal, but anyway... – pgb May 23 '13 at 20:46
  • @pgb: You could leave the category implementation block empty and suppress the compiler warning using `#pragma clang diagnostic ignored "-Wobjc-property-implementation"`. – Martin R May 23 '13 at 21:16
  • @MartinR now we are talking! In any case, I think I'll stick with `mogenerator` for now. – pgb May 23 '13 at 21:18

1 Answers1

0

I had a similar problem, where I created a class extension:

@interface MyClass() <MyProtocol>

@end

And instances of the MyClass were returning NO for conformsToProtocol:@protocol(MyProtocol)

I was able to fix the problem by using a category instead of an extension:

MyClass+MyProtocol.h

@interface MyClass(MyProtocol) <MyProtocol>

@end

MyClass+MyProtocol.m

#import "MyClass+MyProtocol.h"

@implementation MyClass (MyProtocol)

@end

Now instances of my class return YES for conformsToProtocol:@protocol(MyProtocol)

Note that it was necessary to include @implementation MyClass (MyProtocol). Originally, I tried to just include the header file, expecting the <MyProtocol> declaration to be enough, but conformsToProtocol: was still returning NO until I added the @implementation for the category.

charmingToad
  • 1,597
  • 11
  • 18