Core Data NSManagedObject like a base class - ios

I have a base class #interface BaseMailbox : NSManagedObject and I have two children of it.
It seems like it's possible to create an object of my class only the next way:
BaseMailbox *mailbox;
mailbox = [NSEntityDescription
insertNewObjectForEntityForName:#"BaseMailbox"
inManagedObjectContext:context];
So it seems like Core Data objects don't support polymorphism?
EDIT:
Before to create my mailbox object for example I used:
account = [[GoogleMailbox alloc]
initWithFullName
and when I called account.connect - it was a connection with gmail params.
But now account doesnt refer to any of the children object and when I call account.connect- it calles base class method.
EDIT2
BEFORE CORE DATA:
if([_emailAddress.text endsWith:SUFFIX_GOOGLE]){
account = [[GoogleMailbox alloc]
initWithFullName:_fullName.text emailAddress:_emailAddress.text password:_password.text];
}else if([_emailAddress.text endsWith:SUFFIX_YAHOO]){
account = [[YahooMailbox alloc]
initWithFullName:_fullName.text emailAddress:_emailAddress.text password:_password.text];
}else{
..........
BOOL success = [account connect]; // GoogleMailbox or YahooMailbox or ...,depending the account refers to.
CORE DATA:
BaseMailbox* account = [NSEntityDescription
insertNewObjectForEntityForName:#"MailBox"
inManagedObjectContext:context];
}else{
..........
BOOL success = [account connect]; // BaseMailbox

Core Data entities support an inheritance concept.
An entity "A" can be defined as "Parent Entity" of another entity "B" in the
Data Model Inspector. This is reflected in the corresponding managed object subclasses:
B is a subclass of A.
So you could define an entity "BaseMailbox" and make that the parent entity of
"GoogleMailbox" and "YahooMailbox". Attributes which are common to all subclasses are
defined in the parent entity.
Then
[NSEntityDescription insertNewObjectForEntityForName:#"GoogleMailbox"
inManagedObjectContext:context]
returns an GoogleMailbox object, which is a subclass of BaseMailBox.

Related

Creating a memory-only NSManagedObject model

I need to create an instance of a NSManagedObject that will not be saved in CoreData and only in memory.
e.g.:
I have the Item and Log NSManagedObject, and they have relations between them.
I want to be able to create a Log instance without any core data properties, and assign its item property to an Item instance.
I know I can create it in a different, memory-persistence, context (or nil context). But then I can't assign the item property, since my Item instance is in the core-data context.
NSEntityDescription *description = [NSEntityDescription entityForName:#"Log" inManagedObjectContext:defaultContext];
Log *log = [[Log alloc] initWithEntity:description insertIntoManagedObjectContext:nil];
log.item = item;
This code throws an exception when ran:
Illegal attempt to establish a relationship 'item' between objects in different contexts
How can I achieve this in another way?
You can create a NSManagedObjectContext with parent context set to your Log's MOC.
Do you need the relationship to have an inverse? If not, you could use the ObjectID for the item objects as an attribute in the Log entity. You would need to convert the ObjectID to its URIRepresentation, and then convert that to a NSString:
NSURL *itemURI = [item.objectID URIRepresentation];
NSString *itemURIstring = [itemURI absoluteString];
log.itemURI = itemURIstring;
(If item has not yet been saved to the database, it will have a temporary ID - you should test for this with item.objectID.isTemporary otherwise the objectID may change). When you want to find the Item object for a given Log object, reverse the process:
NSURL *itemURI = [NSURL URLwithString:log.itemURI];
NSManagedObjectID *itemObjectID = [self.context.persistentStoreCoordinator managedObjectIDForURIRepresentation:itemURI];
Item *item = [self.context objectWithID:itemObjectID];
Pretty cumbersome!
I guess if you need an inverse, you could do the same (i.e. store a URI for the Log object as a string in Item).

define property of EntityB based on those of EntityA

I have a UILabel that displays a managed object of EntityA. I want use the text of that UILabel as a definition for an EntityB managed object. My first question is, is this possible? I'm trying to pull the text and establish it's properties as those of EntityB here:
NSString *temp = managedObjEntityA.nameA;
managedObjEntityA.name = self.UILabel.text;
self.UILabel.text = temp;
EntityB *textEntityB;
temp = textEntityB.nameB;
My hope is to use the defined textEntityB as reference for a newly created object to establish relationship with:
createdObject.objectToB = textEntityB;
Every version I've tried I get nul for textEntityB. How would I call the managed object of EntityB that matches that of EntityA?
You first have to insert EntityB into your managed object context.
EntityB *newB = [NSEntityDescription insertNewObjectForEntityForName:#"EntityB"
inManagedObjectContext:context];
newB.name = aObject.name;
// or
newB.name = self.label.text;
// establish the (to-one) relationship
aObject.objectToB = newB;

How to get and set Core Data Entity's properties using an array?

I have a CoreData entity , (myEntity) which has assume 10 properties. Is there a way to get the 10 properties in an array and set the property values using said array?
For example:
//To get the property:
NSArray *arrayOfProperties = <Some command>;
...
//and then to set the property value,instead of:
myEntity.property1 = <value>;
//set the property like so:
[[arrayOfProperties objectAtIndex:1] <some command to set the value>];
Something like the following:
// Create the entity in the managed object context:
MyEntity *myEntity = (MyEntity *)[NSEntityDescription insertNewObjectForEntityForName:#"MyEntity" inManagedObjectContext:[self managedObjectContext]];
// Set the properties of the entity:
entity.property1 = arrayOfProperties[0];
entity.property2 = arrayOfProperties[1];
entity.property3 = arrayOfProperties[2];
// etc...

Core Data Adding object in 1 to many relationship gives error

I have two Entities one called Games and one called Teams. The Games entity has a to one relationship to Teams called teams and the Teams entity has a to many relationship to Games called games. (A team can be in many games but a game can only have 1 team. I am using a separate entity for Opponents)
I am selecting a team by using it's ID. Here is my code for adding a team to the Games entity:
Games *newGame = (Games *) [NSEntityDescription insertNewObjectForEntityForName:#"Games" inManagedObjectContext:self.managedObjectContext];
NSFetchRequest *fetchTeams = [[NSFetchRequest alloc] init];
NSEntityDescription *fetchedTeam = [NSEntityDescription entityForName:#"Teams"
inManagedObjectContext:self.managedObjectContext];
[fetchTeams setEntity:fetchedTeam];
NSArray *fetchedTeams = [self.managedObjectContext executeFetchRequest:fetchTeams error:&error];
for (Teams *myTeam in fetchedTeams) {
if (myTeam.teamID == teamid){
newGame.teams = myTeam;
}
}
The error I am getting is: 'NSInvalidArgumentException', reason: 'The left hand side for an ALL or ANY operator must be either an NSArray or an NSSet.'
I don't understand it, newGame.teams is an object of Teams , it is not an NSSet. If I was doing Teams.games it would be an NSSet.
What am I doing wrong?
You've not described what is the data type of variable "teamid" here. Hence, I'm assuming that it must be some primitive type int.
Based on this assumption, you can make the following changes in your code:
if(fetchedTeams!=nil)
{
if(fetchedTeams.count>0)
{
for(Teams *myTeam in fetchedTeams)
{
//check here because coredata stores a number in NSNumber object.
//Hence you've to get the intValue to make a equality check, like below
if(myTeam.teamID.intValue == teamid)
{
//do your stuff here.
//Also check the last part of my answer, I have a question here.
}
}
}
}
In your code you have "newGame.teams = myTeam". What is the data type of "teams" in "newGame" ? is it Teams* or NSSet* ?

Core Data: How to create a Managed Object without referencing the entity by string

To improve the readability of my code, I have been generating Core Data classes for my entities so I can access them using getters and setters (I personally use the dot notation) rather than setValue: forKey:
For example, instead of [aDateObject setValue:nameString forKey:#"name"];
I will use: aDateObject.name = nameString;
I was wondering if there is an equivalent approach for inserting a new managed object into the managed object context. For example, I currently create a new DateTimeFlightDataType with the following:
aDateObject = (DateTimeFlightDataType*)[NSEntityDescription insertNewObjectForEntityForName:#"DateTimeFlightDataType"
inManagedObjectContext:self.managedObjectContext];
Is there a way to create and insert this object into the context using my class (DateTimeFlightDataType) rather than the entity string name for consistency?
You can write:
NSString *name = NSStringFromClass([DateTimeFlightDataType class]);
NSManagedObjectContext *ctx = self.managedObjectContext;
aDateObject = [NSEntityDescription insertNewObjectForEntityForName:name
inManagedObjectContext:ctx];
creating a MO always requires an entity and these are always defined by a string.
the common approach is to somehow make it so the string doesn't need to be hardcoded but can be derived from the MO's class.. typically using NSStringFromClass

Resources