user1085596 user1085596 - 6 months ago 20
Objective-C Question

MagicalRecords adding records with NSSet

I'm just stating to learn CoreData and MR. I'm using the BeerTracker tutorial from Ray Wenderlich and have a problem adding records to an empty database.

// beer.h
@class BeerDetails;



@interface Beer : NSManagedObject

@property (nonatomic, retain) NSString * name;
@property (nonatomic, retain) BeerDetails *beerDetails;

@end

//beerdetails.h:


@interface BeerDetails : NSManagedObject

@property (nonatomic, retain) NSString * image;
@property (nonatomic, retain) NSString * note;
@property (nonatomic, retain) NSNumber * rating;
@property (nonatomic, retain) NSManagedObject *beer;



// where data is being added to the tables:
Beer *paleLager = [Beer createEntity];
paleLager.name = @"Pale Lager";
paleLager.beerDetails = [BeerDetails createEntity];
paleLager.beerDetails.rating = @3;


My table has a one to many, so it uses NSSet:

@property (nullable, nonatomic, retain) NSSet *cells;

It seems to be working on the primary table, but then I set the relationship just as in the example: (Section is one Cell is many)

Section *tempSection = [Section MR_createEntity];
tempSection.button = subButton;
tempSection.cells = [Cell MR_createEntity]; << Warning Here


Incompatible pointer types assigning to 'NSSet * _Nullable' from 'Cell * _Nullable'

If I change it to a 1 to 1 relationship, it seems to work. The part that confuses me is the NSSet *cells.

I can't find any example that uses NSSet and manually load records into the file.

It looks like I don't have to do anything special with NSSet when normally adding records, only when adding them like BeerTracker does. I guess CoreData is looking for a pointer to an NSSet object, but I don't know how to set that up in this line:

tempSection.cells = [Cell MR_createEntity];


Thanks to @sschale, that helped put me in the right direction.
Just so that someone else might benefit, here's the rest:

I created a dictionary with the record values and modified the coredata method:

// added "with:(NSDictionary *) inputData;
- (void)addCells:(NSSet<Cell *> *)values with:(NSDictionary *) inputData;

// this call create the entity and passes the dictionary of keys/values
[tempSection addCells:(NSSet *)[Cell MR_createEntity] with:myDictionary];

// here's an example of changing the values inside the 'addCells:with:' method
[values setValue:[inputData objectForKey:@"overpic"] forKey:@"overpic"];
[values setValue:[inputData objectForKey:@"pictitle"] forKey:@"pictitle"];
[values setValue:[inputData objectForKey:@"position"] forKey:@"position"];


I don't know if this is the best way, but so far it seems to be working. Ran across this article about performance that someone might be interested in:
http://www.cocoawithlove.com/2009/11/performance-tests-replacing-core-data.html

Answer

Here is the syntax to create a set in Objective C with a single object:

tempSection.cells = [NSSet setWithObject:[Cell MR_createEntity]];

To do it with multiple items, use:

tempSection.cells = [NSSet setWithObject:[Cell MR_createEntity], [Cell MR_createEntity], ..., nil];

More commonly, you want to use the accessors that are created for you in your +CoreDataProperties.h file:

- (void)addCellsObject:(Cell *)value;
- (void)removeCellsObject:(Cell *)value;
- (void)addCells:(NSSet<Cell *> *)values;
- (void)removeCells:(NSSet<Cell *> *)values;

So in this case, you'd call:

[tempSection addCellsObject:[Cell MR_createEntity]];