many-to-one relation core data - xcode

I am obviously new in Core Data, I have read quite a lot about the topic from Apple and from countless other sources. However, none seems to treat the many-to-one relation in a way for a newbie like me to understand. I seems to be fine with one-to-one relation, but I have some difficulties on understanding many-to-one relation.
My problem is as follow:
I am working on a small project to practice Core Data. In my project, there are two entities:Person and Note and they are related as follow:
(Sorry, couldn't add the picture)
A Person can have several notes, but Note can only have one owner, Person. Person entity is related with a one-to-many relation (double arrows pointing to the entity: Note), while the entity Note is related with a many-to-one (single arrow pointing to Person)
This is what I have so far:
Note.h
#class Person;
#interface Note : NSManagedObject
#property (nonatomic, retain) NSDate * noteCreateDate;
#property (nonatomic, retain) NSString * noteUser;
#property (nonatomic, retain) Person *person;
Person.h
#class Note, Organise;
#interface Person : NSManagedObject
#property (nonatomic, retain) NSString * personAddress;
#property (nonatomic, retain) NSData * personAvatar;
#property (nonatomic, retain) NSString * personBDay;
#property (nonatomic, retain) NSDate * personFutureDate;
#property (nonatomic, retain) NSString * personGender;
#property (nonatomic, retain) NSString * personName;
#property (nonatomic, retain) NSString * personRelation;
#property (nonatomic, retain) NSSet *notes;
#property (nonatomic, retain) NSSet *organises;
#end
#interface Person (CoreDataGeneratedAccessors)
- (void)addNotesObject:(Note *)value;
- (void)removeNotesObject:(Note *)value;
- (void)addNotes:(NSSet *)values;
- (void)removeNotes:(NSSet *)values
In my view controller I am trying to save the notes as follow:
NSManagedObjectContext *context = [self managedObjectContext];
Note *newNote;
newNote = (Note *) [NSEntityDescription insertNewObjectForEntityForName:#"Note" inManagedObjectContext:context];
// Saving the notes
newNote.noteUser = noteTextView.text;
newNote.noteCreateDate = added;
[newNote setPerson:newNote.person];
///////////////Saving to the DataBase /////////
NSError *error = nil;
if ([self.managedObjectContext hasChanges]) {
if (![self.managedObjectContext save:&error]) { //save failed
NSLog(#"Save Failed: %#", [error localizedDescription]);
}
else {
NSLog(#"Save Succeeded");
}
}
It is saving the data in the database fine, but the problem is: There is no relationship between Person and Notes in the database. The column for person in the database is empty (not showing to whom the note belong to).
I have tried several things to try to link the person with the note, NONE of them seems to work. So, it seems that I am stucked and I would very much appreciate some help.
This is the latest tutorial I used for help:
http://brandontreb.com/core-data-quicktip-inverse-relationships
https://itunes.apple.com/fr/itunes-u/advanced-iphone-development/id407243028?l=en&mt=10
Thank you.

Your code does not create any relationship between the Note and a Person. This:
[newNote setPerson:newNote.person];
is the same as newNote.person = newNote.person; and does not change anything.
You must create a Person object (or fetch an existing Person) and then set
newNote.person = thePerson;
to establish the relationship.

Related

How does RestKit map a out key to a model?

This is my json and managed object model:
{
lasttime: 1387351751288
AreaList: [
{
provinceid: 1,
provincename: "a",
count: 1,
},
{
provinceid: 2,
provincename: "b",
count: 2,
}
]
}
#interface Province : NSManagedObject
#property (nonatomic, retain) NSString * provinceid;
#property (nonatomic, retain) NSString * provincename;
#property (nonatomic, retain) NSNumber * count;
#property (nonatomic, retain) NSNumber * lasttime;
#end
I want to map the "lasttime" into the Province.lasttime, how should I modify the mapping?
To copy direct into the object can not be done during the mapping because you can't both index into the array and use things outside the array at the same time.
I would consider mapping the time into its own object and then connect via a relationship with the provinces. Again, this can't be done entirely in the mapping for the same reason, so you would need to connect the objects in the success block.
Using the success block to make the connection would work just as well without the relationship if you map the time into an object and then copy the value across.
Try this:
[mapping addAttributeMappingsFromDictionary:#{
#"#parent.lasttime" : #"lasttime"
}];

one to many relationship not working (Restkit 0.20) addRelationshipMappingWithSourceKeyPath

I have a simpe one to many relationshipim my JSON and would like to map this into Objects (NOT Core Data entities). Mapping the poducts is working fine. But every product has an array of tracks that is not mapped.
This is the JSON:
Here is the code:
Product.h
#import <Foundation/Foundation.h>
#interface Product : NSObject
#property (nonatomic, strong) NSString* productid;
#property (nonatomic, strong) NSString* title;
#property (nonatomic, strong) NSString* artist;
//...
#property (nonatomic, strong) NSMutableArray *tracks;
Track.h
#import <Foundation/Foundation.h>
#interface Track : NSObject
#property (nonatomic, strong) NSString *artist;
#property (nonatomic, strong) NSString *title;
#property (nonatomic, strong) NSString *mixversion;
Here the code to request the JSON and map the response to Objects
/// Create Mappers for Product and Track
RKObjectMapping *mappingForProduct = [RKObjectMapping mappingForClass:[Product class]];
[mappingForProduct addAttributeMappingsFromArray:#[#"productid", #"title", #"tracks"]];
RKObjectMapping *mappingForTrack = [RKObjectMapping mappingForClass:[Track class]];
[mappingForTrack addAttributeMappingsFromArray:#[#"artist",#"title",#"mixversion"]];
/// assign relationship product-track
[mappingForProduct addRelationshipMappingWithSourceKeyPath:#"tracks" mapping:mappingForTrack];
/// setup responseDescriptor
NSString *key_path = #"products";
RKResponseDescriptor *responseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:mappingForProduct
pathPattern:nil
keyPath:key_path
statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful)];
/// Create Manager, connect responseDescriptor and execute
RKObjectManager *manager = [RKObjectManager managerWithBaseURL:[NSURL URLWithString:#"myRequestString"]];
[manager addResponseDescriptor:responseDescriptor];
[manager getObject:nil path:#"" parameters:nil
success:^(RKObjectRequestOperation *operation, RKMappingResult *mappingResult)
{
self.productsArray = [NSMutableArray arrayWithArray:mappingResult.array];
}
failure:^(RKObjectRequestOperation *operation, NSError *error)
{
NSLog(#"Error: %#", error);
}
This gives an assertion error:
*** Assertion failure in -[RKObjectMapping addPropertyMapping:], /Users/.../Pods/RestKit/Code/ObjectMapping/RKObjectMapping.m:235
The magic should happen in this line:
[mappingForProduct addRelationshipMappingWithSourceKeyPath:#"tracks" mapping:mappingForTrack];
... but for some reason it doesn't.
I've searched quite some sources on SO and the documentation, tried quite some combinations of keypath changed, but nothing will give the required result. A lots of the availble sample code is regarding older versions of RestKit or deals with Core Data. I just want to get mapped objects, no Core Data entities.
Thanks in advance for any hint.
You're just trying to add a mapping for tracks twice. It should be a relationship mapping, not an attribute mapping. Change the mappingForProduct to:
[mappingForProduct addAttributeMappingsFromArray:#[#"productid", #"title"]];
And the cause of the exception should be removed.

Declare a Mutable Dictionary (to use addEntriesFromDictionary) in header file

I need to use several times:
[mutableDict addEntriesFromDictionary:dictionary];
I don't know how to declare mutableDict in the header file. I try with:
#property (nonatomic, assign) NSMutableDictionary *mutableDict;
#property (nonatomic, retain) NSMutableDictionary *mutableDict;
#property (nonatomic, retain, readwrite) NSMutableDictionary *mutableDict;
And more...
How I must to declare this NSMutableDictionary??
In your header file use #property (nonatomic, retain) NSMutableDictionary *mutableDict; if your are not using ARC, or #property (nonatomic, strong) NSMutableDictionary *mutableDict; if you are using ARC.
In your implementation include #synthesize mutableDict; or better #synthesize mutableDict = _mutableDict; somewhere after #implementation YourClass.
You should also initialize it with something like _mutableDict = [[NSMutableDictionary alloc] init];
If you do not need your mutable dictionary used from outside (ex: [myobject.mutableDict addEntriesFromDictionary:dictionary]; you better not define it in your header file but in your implementation like:
#implementation YourClass {
NSMutableDictionary *_mutableDict;
}
and initialize it like shown above

MVC iOS breakout game design

I have the following models in my breakout like game:
Ball.h
Block.m
GamePlay.m
Paddle.h
Paddle.m
I also have the following views:
BallView
BlockVIew
PaddleView
My question is, when I change a property in the model, I have to change the property in the view also. For example:
Ball Model:
#interface Ball : NSObject
#property (nonatomic, strong) NSNumber *radius;
#property (nonatomic, strong) NSNumber *xSpeed;
#property (nonatomic, strong) NSNumber *ySpeed;
#property (nonatomic, strong) NSNumber *xDirection;
#property (nonatomic, strong) NSNumber *yDirection;
#property (nonatomic) CGPoint location;
#property (nonatomic, strong) UIColor *color;
#end
Ball View:
#interface BallView : UIView
#property (strong, nonatomic) UIColor *color;
#property (nonatomic) int radius;
#end
When the model has its properties changed, I have such as location, or color. I have to update these same properties in the view. Should I NOT track location and color in my model?
I think the main point in MVC is maintainability over time. If you decide you need an entirely different view of your game tomorrow, the model code can stay the same, so you can focus on modifying just the view part.
Also, if you know you need some data about the game's state, you know where you can find it - in the model. For example, you might want to transmit the ball's location over the internet to your friend, if he is interested in watching you breaking blocks.
As you can probably guess from the last two paragraphs, you should indeed store and update the location and color of the ball in the model. The view shouldn't be the owner of app state.

Binding problem with a NSValue that contains NSPoint

I have this managedObject subclass, position rappresent a NSPoint. In a XIB I want two NSTextField like this
where one display position.x value and the other display position.y. I tried to bind the NSTextField to a "selection.position.x" and "selection.position.y" keyPath of a NSArrayController that manage Frames
I get this error::
[ setValue:forUndefinedKey:]: this class
is not key value coding-compliant for the key x.
So i checked KVC:
Frame.h
#interface Frame : NSManagedObject {
#private
}
#property (nonatomic, retain) NSNumber * order;
#property (nonatomic, retain) NSNumber *visible;
#property (nonatomic, retain) NSValue *position;
#property (nonatomic, retain) NSNumber *scale;
#property (nonatomic, retain) Sprite *sprite;
#property (nonatomic, retain) Resource *resource;
//test
#property (nonatomic, retain) NSValue *frame;
#end
In -(void)awakeFromInsert I try this code:
-(void)awakeFromInsert
{
[super awakeFromInsert];
self.position = [NSValue valueWithPoint:NSPointFromCGPoint(CGPointZero)];
//[self.position setValue:[NSNumber numberWithFloat:50.0f] forKey:#"x"];
[self setValue:[NSNumber numberWithFloat:1.0f] forKeyPath:#"scale"];
[self setValue:[NSNumber numberWithFloat:10.0f] forKeyPath:#"frame.origin.x"];
[self setValue:[NSNumber numberWithFloat:10.0f] forKeyPath:#"position.x"];
}
The first and second KVC setValue works, the third crash with the same message above
[ setValue:forUndefinedKey:]: this class is not key value coding-compliant for the key x.
I don't understand why, any help is appreciate.
NSValue objects are not mutable. To change a NSValue property, you have to create a new NSValue object and then assign it to the property.

Resources