Creating a memory-only NSManagedObject model - ios

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).

Related

iOS Core Data <fault after searching

All, I am having problems with Core Data.
I have a method that queries all data which matches a jobId
- (JobSummary*)summaryForJobId:(NSInteger)jobId {
NSFetchRequest* request = [[NSFetchRequest alloc] initWithEntityName:[JobSummary entityName]];
request.predicate = [NSPredicate predicateWithFormat:#"jobId = %D", jobId];
JobSummary* summary = [[self.context executeFetchRequest:request error:nil] lastObject];
NSLog(#"DB Summary: %#", summary);
[request setReturnsObjectsAsFaults:NO];
return summary;
}
When called and I log out it works perfect, however when I call it from a seperate view controller like so;
JobSummary *retrievedDictionary = [[FSScheduleDatabaseTransaction new] summaryForJobId:jobid];
When I log out retrievedDictionary it spits out this;
<JobSummary: 0x12de24a0> (entity: JobSummary; id: 0xb3c19b0 <x-coredata://7E9F6C6E-B4A0-4450-8905-184C6C8FB60D/JobSummary/p169> ; data: <fault>)
Any help much appreciated!
It is giving you the log correctly. When ever you try to print the ManagedObject you'll only see a fault in logs.
A fault is a placeholder object that represents a managed object that has not yet been fully realized, or a collection object that represents a relationship:
A managed object fault is an instance of the appropriate class, but its persistent variables are not yet initialized.
A relationship fault is a subclass of the collection class that represents the relationship.
So, in short, unless you try to access those properties, CoreData wont fill property values. It will have a fault. Just trying to log the ManagedObject, without accessing its properties previously, will only show fault.

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 Store a ABRecordRef Object in CoreData

I want to store a ABRecordRef Object i.e in the format of <CPRecord: 0xa2a3500 ABPerson> using Coredata.
While I have tried to store like
NSEntityDescription *entityDescriptionStrings = [NSEntityDescription entityForName:#"ContactsStrings" inManagedObjectContext:context];
ContactsStrings *contactsManagedObjectStrings = [[ContactsStrings alloc] initWithEntity:entityDescriptionStrings insertIntoManagedObjectContext:context];
ABRecordRef recordRef = CFArrayGetValueAtIndex(contactInfoArray, i);
[contactsManagedObjectStrings setValue:(__bridge id)(recordRef) forKey:#"record"];
I am getting a crash saying
record I have taken as Integer32 Datatype.
Terminating app due to uncaught exception NSInvalidArgumentException,
reason: 'Unacceptable type of value for attribute: property =
"record"; desired type = NSNumber; given type = __NSCFType; value =
.
Try this,
ABRecordRef recordRef = CFArrayGetValueAtIndex(contactInfoArray, i);
ABRecordId recId = ABRecordGetRecordID(recordRef);
NSNumber *recordId = [NSNumber numberWithInt:(int)recId];
[contactsManagedObjectStrings setValue:recordId forKey:#"record"];
to retrive
//recordId is the value of record key from managedobject
ABRecordId recId = (ABRecordId)[recordId intValue];
ABRecordRef recordRef = ABAddressBookGetPersonWithRecordID(ddressBook, recId);
It will better you don't save ABRecordRef, but you should save ABRecordRefID in your coredata. Here is the link which can give you more detail in this. I always prefer to do in that way.
The issue is that you are storing an object reference within a database. A reference points to memory that is valid at only that point in time. If you store the object reference and then later reload the reference from the database (especially after an app restart), it will point to invalid memory.
Instead store the actual data from the object into the database, and not the object reference, or perhaps the record ID, as returned from ABRecordGetRecordID().

Core Data NSManagedObject like a base class

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.

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