0

I'm trying to override the setter of an NSManagedObject so that I can pass in an object of a different type, do a transformation and then set the property. Something like this:

- (void)setContentData:(NSData *)contentData
{
    NSString *base64String;
    // do some stuff to convert data to base64-encoded string
    // ...
    [self willChangeValueForKey:@"contentData"];
    [self setPrimitiveValue:base64String forKey:@"contentData"];
    [self didChangeValueForKey:@"contentData"];
}

So, in this case the contentData field of my NSManagedObject is an NSString *, and I want to allow the setter to accept an NSData * which I would then convert to an NSString * and save it to the model. However, if I try to do this I get warnings from the compiler about trying to assign an NSData * to an NSString *:

myObject.contentData = someNSData;

-> Incompatible pointer types assigning to 'NSString *' from 'NSData *__strong'

Is there a better way to go about this, or perhaps I should avoid the setters altogether and create custom "setters" that allow me to pass in the NSData * and set the NSString * field without a compiler warning?

Jamie Forrest
  • 10,895
  • 6
  • 51
  • 68

2 Answers2

3

I think this is an instance where your fighting with the tools and frameworks is a significant design smell. Retreat from this notion of trying to override the expected data type of a fundamental property for your class.

You didn't say whether the NSManagedObject you are subclassing is under your control. If it's going to be part of your design to have it be something of a template for management of other types of contentData than NSString, then declare it as type id in the root class and specialize in the subclasses. That should prevent the warning.

Probably, you want to follow a Cocoaism: don't subclass. Can you achieve whatever functionality you're looking for from the superclass by say extracting it into a helper class that is held as a property by each of the varying-behavior managed object classes?

danielpunkass
  • 17,527
  • 4
  • 24
  • 38
  • thanks, I like your idea of the helper class that gets set as a property on the NSManagedObjects. – Jamie Forrest Jul 05 '12 at 19:05
  • To clarify, I was thinking of it more from another angle: what is it about the parent NSManagedObject that makes it worth subclassing? What do you gain by having "MyObject2" be a subclass of "MyObject1" at all? – danielpunkass Jul 05 '12 at 19:07
  • In this case, you'd be gaining all of the "magic" that happens when the value changes and I call, e.g., [self willChangeValueForKey:@"contentData"]; – Jamie Forrest Jul 05 '12 at 19:13
  • But, for example, you can implement another NSManagedObject class that also has a "contentData" property that in its case is an NSData* instead of NSString. What do you get *precisely* from subclassing MyObject1? – danielpunkass Jul 06 '12 at 11:19
  • The reason why contentData is NSString, in my case, is because I am interfacing with a web service treats the binary data as a base64-encoded string. I am using RestKit to manage the serialization & deserialization & connections to core data. In the end I am simply using custom setters and getters like `- (void)setContentDataWithData:(NSData *)contentData` and `- (NSData *)dataFromContentData`. Thoughts on that approach? – Jamie Forrest Jul 06 '12 at 13:39
1

following up on my "setContentData: (id) contentData" comment, try something like this:

- (void)setContentData:(id)thingToWorkWith
{
    NSString * base64String = nil;

    if(thingToWorkWith isKindOfClass: [NSData class])
    {
       // convert data to string   
    }


    if(thingToWorkWith isKindOfClass: [NSString class])
    {
        // set up base64 string properly
    }

    if(base64String)
    {
        // do some stuff to convert data to base64-encoded string
        // ...
        [self willChangeValueForKey:@"contentData"];
        [self setPrimitiveValue:base64String forKey:@"contentData"];
        [self didChangeValueForKey:@"contentData"];
    }
}

Make sure to get rid of the "@synthesize" bit for contentData in your .m file, create a "getter" method as well, and because you're using "id" for the setter parameter, you may have to adjust your "@property" declaration a bit. I haven't tried exactly what you are attempting to do (i.e. no warranties on this technique).

Michael Dautermann
  • 88,797
  • 17
  • 166
  • 215
  • It's an NSManagedObject so I want to avoid removing the @ property and @ dynamic stuff. – Jamie Forrest Jul 05 '12 at 18:32
  • I wasn't saying remove the "`@property`" declaration, you need that. But if you want to provide your own setter & getter, you need to remove the "`@synthesize`" line that automatically creates setters & getters for you. – Michael Dautermann Jul 05 '12 at 18:55