Jeremy Kelleher
Jeremy Kelleher

Reputation: 287

use of undeclared identifier core data

I'm using core data in Xcode 7 beta 6 and I just generated categories and managed object subclasses for each of my entities. The issue is that when I try to utilize the properties created from the attributes in my model, I get a "use of undeclared identifier" error. I was under the impression that I was supposed to put custom behavior in the managed object subclass that were generated, however I was not clear on how I could use the properties from the categories in the managed object subclass, so I placed the custom behavior in the categories as shown below. I feel like I'm merely missing an import statement, but I'm not sure. I understand I'm using beta software.

Core Data Model: enter image description here

Thought+CoreDataProperties.h:

#import "Thought.h"

NS_ASSUME_NONNULL_BEGIN

@interface Thought (CoreDataProperties)

@property (nullable, nonatomic, retain) NSString *objectId;
@property (nullable, nonatomic, retain) id recordId;
@property (nullable, nonatomic, retain) Collection *parentCollection;

@property (nullable, nonatomic, retain) NSNumber *placement;

@property (nullable, nonatomic, retain) NSString *text;
@property (nullable, nonatomic, retain) NSString *extraText; // allows for extra description text to be set. Should be in smaller print than headline text and should only appear as an option in text != nil
@property (nullable, nonatomic, retain) NSSet<Photo *> *photos;
@property (nullable, nonatomic, retain) id location; // place a CLLocation here

@property (nullable, nonatomic, retain) id tags; // place an NSArray here

@property (nullable, nonatomic, retain) NSDate *creationDate;

#pragma mark - Initializers

/*!
 @abstract this method converts a CKRecord into a Thought object
 @discussion parentCollection will still be nil after this method executes
 */
-(nullable instancetype) initWithRecord: (nonnull CKRecord *) record;

/*!
 @abstract this method converts a CKRecord into a Thought object. photos set is not populated
 */
-(nullable instancetype)initWithRecord: (nonnull CKRecord *) record collection: (nonnull Collection *) collection;

/*!
 @abstract Creates a new Thought object with generic recordId, objectId, placement, and photos array
 @discussion parentCollection will still be nil after this method executes
 */
-(nullable instancetype) init;

   … other methods

@end

@interface Thought (CoreDataGeneratedAccessors)

- (void)addPhotosObject:(Photo *)value;
- (void)removePhotosObject:(Photo *)value;
- (void)addPhotos:(NSSet<Photo *> *)values;
- (void)removePhotos:(NSSet<Photo *> *)values;

@end

NS_ASSUME_NONNULL_END

Thought+CoreDataProperties.m:

#import "Thought+CoreDataProperties.h"

@implementation Thought (CoreDataProperties)

@dynamic creationDate;
@dynamic extraText;
@dynamic location;
@dynamic objectId;
@dynamic placement;
@dynamic recordId;
@dynamic tags;
@dynamic text;
@dynamic parentCollection;
@dynamic photos;

-(nullable instancetype) init {
    self = [super init];
    if (self) {

       // THIS IS WHERE I GET MANY ERROR FOR USE OF UNDECLARED IDENTIFIER
        _objectId = [IdentifierCreator createId];

        _recordId = [[CKRecord alloc] initWithRecordType:THOUGHT_RECORD_TYPE zoneID:[[CKRecordZone alloc] initWithZoneName:ZONE_NAME].zoneID].recordID;

        _photos = [NSArray new];

        _placement = [NSNumber numberWithInt:0];

        _creationDate = [NSDate date];
    }
    return self;
}

-(instancetype) initWithRecord:(nonnull CKRecord *)record {
    self = [super init];
    if (self) {
        _objectId = [record objectForKey:OBJECT_ID_KEY];

        _recordId = [record recordID];

        _text = [record objectForKey:TEXT_KEY];
        _extraText = [record objectForKey:EXTRA_TEXT_KEY];
        _location = [record objectForKey:LOCATION_KEY];

        _photos = [NSSet new];

        _tags = [record objectForKey:TAGS_KEY];

        _placement = [record objectForKey:PLACEMENT_KEY];
        _creationDate = record.creationDate;
    }
    return self;
}

-(instancetype) initWithRecord:(CKRecord *)record collection:(Collection *)collection {
    self = [self initWithRecord:record];
    self.parentCollection = collection;
    return self;
}

Thought.h:

#import <Foundation/Foundation.h>
#import <CoreData/CoreData.h>
#import "Frameworks.h" // includes Frameworks I'm using and some string constants
#import "ForFundamentals.h" // includes mostly string constants
#import "Photo.h"
#import "Collection.h"

@class Collection, Photo;

NS_ASSUME_NONNULL_BEGIN

@interface Thought : NSManagedObject

// I think I should put method declarations here

@end

NS_ASSUME_NONNULL_END

#import "Thought+CoreDataProperties.h"

Thought.m:

#import "Thought.h"
#import "Collection.h"
#import "Photo.h"

@implementation Thought

// I think I should put method implementations here

@end

Upvotes: 0

Views: 1375

Answers (2)

Hal Mueller
Hal Mueller

Reputation: 7665

Subclasses of NSManagedObject do their initialization in awakeFromInsert or awakeFromFetch. Don't override init or implement initWith.... You have to wait until the object is instantiated, and alive within an NSManagedObjectContext, before you can set its properties.

Don't assign collection instances to your ivars corresponding to Core Data relationships (i.e. _photos, parentCollection. Core Data will do that for you when you insert or fetch the object.

Instead of your init methods, rethink your approach. Write a method insertInManagedObjectContext:withSKRecord. That method calls -insertNewObjectForEntityForName:@"Thought" inManagedObjectContext:foo, which returns an instance of Thought. Now, with that istance, set the objecgtID, recordID, etc–but with your accessors, not by directly banging the instance variables.

Upvotes: 1

Jeremy Kelleher
Jeremy Kelleher

Reputation: 287

So it seems that although I can't use _name = @"string" syntax to set property values, I can use method syntax, like [self setName: @"string"]. This seems very strange to me. However, the method syntax does work in both the subclass and the category so I guess problem solved… for now.

UPDATE

I didn't understand @dynamic. This post helped clear it up. I can't use _propertyName because the accessor methods are dynamically created by core data.

Upvotes: 0

Related Questions