1

I made few classes via Core Data. And I need some additional @propertys for one of that classes in runtime. This @propertys are responsible for download progress and I don't want to store them in Core Data DB. I tried to use a separate extension class:

@interface MyClass ()

    {
        CGFloat _downloadProgress;
        NSInteger _downloadErrorCounter;
        BOOL _downloadAllStuff;
        BOOL _downloadUserCanceled;
    }

    @property (nonatomic, assign) CGFloat downloadProgress;
    @property (nonatomic, assign) NSInteger downloadErrorCounter;
    @property (nonatomic, assign) BOOL downloadAllStuff;
    @property (nonatomic, assign) BOOL downloadUserCanceled;

@end

But private variables are not visible out of MyClass, and @propertys compile all right, but in runtime i get -[MyClass setDownloadErrorCounter:]: unrecognized selector sent to instance. Can anyone suggest me some solution?

Valentin Shamardin
  • 3,569
  • 4
  • 34
  • 51
  • Do you have @dynamic in you m-file? – Mikael Jul 01 '13 at 08:04
  • 2
    Did you `@synthesize` the setters and getters? Even in Modern Objective-C were you don't need to `@synthesize` anymore it appears that it's necessary to synthesize in NSManagedObject subclasses. The compiler should show you a warning that you have to define a setter and getter for your properties too. – Matthias Bauch Jul 01 '13 at 08:04
  • No i haven't. It's Core Data, so i can't change Core Data classes. And I use a new file MyClass_Download.h to declare properties. Where can I synthesize them? – Valentin Shamardin Jul 01 '13 at 08:08
  • You don't need to declare private variables like that. `@property` will create the `_...` private variable for you and synthesise it properly too. All you need is the `@property` line. Why don't you make a new class which is a subclass of the core data class? Then you wouldn't have to worry about your new properties being overwritten. – Thomas Clayson Jul 01 '13 at 08:12
  • @ThomasClayson: That does not work (or is at least difficult). NSManagedObject subclasses *must* be initialized using `initWithEntity:insertIntoManagedObjectContext:`, and even if you call that from a custom subclass, it returns an object of the entities class (I just tried it). I don't say that it is impossible, but it is not straightforward either. – Martin R Jul 01 '13 at 08:30

3 Answers3

6

The easiest solution (if you don't want to modify the Xcode generated class files) is to add the properties to the Core Data model and define the properties as transient. Transient properties are not saved to the store file.

Another option is to use a tool like "mogenerator", which generates two class files for each entity, one for the Core Data properties (which is overwritten if the the model changes), and one for your custom properties (which is not overwritten).

Update: Starting with Xcode 7, Xcode creates both a class and a category for each managed object subclass, compare NSManagedObject subclass property in category. Custom properties can be added to the class definition which is not overwritten when the model changes.

Community
  • 1
  • 1
Martin R
  • 529,903
  • 94
  • 1,240
  • 1,382
1

Just add

@synthesize downloadErrorCounter = _downloadErrorCounter;
...

in @implementation. Note, not @dynamic.

Kjuly
  • 34,476
  • 22
  • 104
  • 118
0

When trying to use the @synthesize solution i got the error:

@synthesize not allowed in a category's implementation.

Solution was to use associated objects as described in this blog: http://kaspermunck.github.io/2012/11/adding-properties-to-objective-c-categories/

MyManagedObject+Additions.h

@property (strong, nonatomic) NSString *test;

MyManagedObject+Additions.m

NSString const *key = @"my.very.unique.key";

- (void)setTest:(NSString *)test
{
    objc_setAssociatedObject(self, &key, test, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}

- (NSString *)test
{
    return objc_getAssociatedObject(self, &key);
}
qRis
  • 86
  • 6