Unable to load NSMutableArray from CoreData store - core-data

I have a NSMUtableArray that I am trying to load from a Core Data store (there is valid data in the store); this is the code:
[unsortedArray addObject:storedServices.aCustomServices1];
[unsortedArray addObject:storedServices.aCustomServices2];
The array is defined as:
#property (nonatomic, retain) NSMutableArray *unsortedArray;
I can load the array using static data which works:
unsortedArray = [NSMutableArray arrayWithObjects:
NSLocalizedString(#"Property1",nil),
NSLocalizedString(#"Property2",nil),nil];
The problem is although there is valid data in the CD store, the array remains empty. I have searched Google and SO but found nothing related. Why can I not load from the Core Data store?

I'll take a punt that you haven't allocated unsortedArray. Try:
self.unsortedArray = [NSMutableArray array];
[self.unsortedArray addObject:storedServices.aCustomServices1];
[self.unsortedArray addObject:storedServices.aCustomServices2];
This assumes you have unsortedArray getter/setter methods that conform to normal MRR memory management practices. This is as simple as using #synthesize unsortedArray (although newer versions of clang do this for you, I'd still explicitly add it).
Note that:
self.unsortedArray = [NSMutableArray array];
Should be in your init method.

Related

Core Data: Copying NSManagedObject Using Category

I have two entities:
Ticket
TicketResolved
Both entities have the same attributes. What would be the the most efficient way to copy a Ticket NSManagedObject to TicketResolved NSManagedObject?
I'm thinking using a Category: Ticket+Copy be the least expensive way? If so, I would have to #import both Ticket and TicketResolved in the Category file.
Here is what I came up with, can someone please advise if this is the right way of going about it. I'm using NSManagedObjectSubclass for each entity.
Method in Ticket+Copy:
-(TicketResolved *)copyObjects:(Ticket *)ticket
{
TicketResolved *ticketResolved = [NSEntityDescription insertNewObjectForEntityForName:#"TicketResolved" inManagedObjectContext:self.managedObjectContext];
ticketResolved.attribute = ticket.attribute;
// Assign rest of the ticketResolved attributes values this way
return ticketResolved;
}
Now calling the Method
#import Ticket;
#import Ticket+Copy;
#implementation
....
Ticket *ticket = [NSEntityDescription insertNewObjectForEntityForName:#"Ticket" inManagedObjectContext:self.managedObjectContext];
TicketResolved *newTicketResolved = [ticket copyObjects:ticket];
// 'newTicketResolved' now has all the keys/values that 'ticket' had.
Is this a right approach or is there a simpler way to do this?
If Ticket and TicketResolved actually have the same attributes, the most efficient option is to:
Get rid of TicketResolved
Add a boolean flag on Ticket named resolved that you can set to YES when the ticket is resolved.
Use this attribute it fetch requests to get either resolved or non-resolved tickets, whichever you need.
Then you don't actually need to copy any data, and not doing work is always more efficient than doing it.
If for some reason you really want two separate entities with the same attributes, basically you have it, you need to create a TicketResolved instance and have your code copy over every attribute value. The only major problem with your code is lines like this:
Ticket *ticket = [Ticket alloc]init];
You can't create managed objects like that, because you're not calling the designated initializer. You need to either use -[NSManagedObject initWithEntity:insertIntoManagedObjectContext:] or else use +[NSEntityDescription insertNewObjectForEntityForName:inManagedObjectContext:].
Thanks to #Tom, I did correct my error in the question.
Below is the solution that worked for me:
TicketResolved *ticketResolved = [NSEntityDescription insertNewObjectForEntityForName:#"TicketResolved" inManagedObjectContext:self.managedObjectContext];
NSArray *keys = [[[ticket entity] attributesByName] allKeys];
NSDictionary *dict= [ticket dictionaryWithValuesForKeys:keys];
[ticketResolved setValuesForKeysWithDictionary:dict];
The code above does not copy the Relationships Objects. For that I had to use the code below:
ticketResolved.relationshipObject = ticket.relationshipObject;

NSMutableArray in NSUserDefault

i've a problem with my table!
i use a parsing tableview but when i change view, my table loses data. So i decide to save all data to nsuserdefault; but, here the problem, NSUserDefault warns me:
"Note that dictionaries and arrays in property lists must also contain only property values."
NB: itemsToDisplay is a NSMutableArray and contain title, url, data and summary of parsedItems.
Well, here my code:
self.itemsToDisplay = [[[NSUserDefaults standardUserDefaults] arrayForKey:#"items"] mutableCopy];
if (!self.itemsToDisplay) {
self.itemsToDisplay = [[NSMutableArray alloc] init];
}
self.itemsToDisplay = [[NSMutableArray alloc]init];
self.itemsToDisplay = [parsedItems sortedArrayUsingDescriptors:
[NSArray arrayWithObject:[[[NSSortDescriptor alloc] initWithKey:#"date"
ascending:NO] autorelease]]];
[[NSUserDefaults standardUserDefaults] setObject:self.itemsToDisplay forKey:#"items"];
[[NSUserDefaults standardUserDefaults] synchronize];
I suppose the problem is setObject:self.itemsToDisplay, but i don't know how solve it.
Thank You guys..
First lets mention that the table cannot lose data because it does not hold any user data. The data is either provided through bindings or through delegation see NSTableViewDataSource in Apples documentation).
Second, the first three assignments to self.itemsToDisplay serve no purpose (unless you have side-effects in the setter) because they are all overridden by the last assignment.
Finally, if this code is already in the delegate then the delegate should be instantiated in your NIB file for the data to survive past a view swap. If your delegate is an object that is instantiated with your view it will also die with it along with all of the data and writing to the user-defaults is a bad idea for what you are trying to achieve. Simply set the delegate to an object whose lifetime is greater than that of both views.
self.itemsToDisplay = [parsedItems sortedArrayUsingDescriptors:
[NSArray arrayWithObject:[[[NSSortDescriptor alloc] initWithKey:#"date"
ascending:NO] autorelease]]];
//First lets encode it
NSUserDefaults *userDefault=[NSUserDefaults standardUserDefaults];
NSData *myEncodedObject = [NSKeyedArchiver archivedDataWithRootObject:self.itemsToDisplay];
[userDefault setObject:myEncodedObject forKey:[NSString stringWithFormat:#"sample"]];

CoreData, NSManagedObject fetch or create if not exists

I am trying to parse a lot of text files and organize their contents as managed objects. There are a lot of duplicates in the text files, so one of the "collateral" tasks is to get rid of them.
What i am trying to do in this respect is to check whether an entity with the given content exists, and if it doesn't, i create one. However, i have different entities with different attributes and relationships. What i want is a kind of function that would take a number of attributes as an input and return a new NSManagedObject instance, and i wouldn't have to worry if it was inserted into the data store or fetched from it.
Is there one?
I must also say that i am a noob at core data.
Some more detail, if you want:
I am trying to write a sort of dictionary. I have words (Word{NSString *word, <<-> Rule rule}), rules (Rule{NSString name, <->>Word word, <<->PartOfSpeech partOfSpeech, <<-> Ending endings}), parts of speech (PartOfSpeech{NSString name, <<-> Rule rule}) (i hope the notation is clear).
Two words are equal, if they have the same word property, and "linked" to the same rule. Two rules are the same, if they have the same endings and part of speech.
So far i've written a method that takes NSPredicate, NSManagedObjectContext and NSEntityDescription as an input, and first queries the datastore and returns an entity if it finds one, or creates a new one, inserts it into the datastore and returns it. However, in this case I cannot populate the new entity with the necessary data (within that method), so i have to either pass an NSDictionary with the names of attributes and their values and insert them, or return by reference a flag as to whether i created a new object or returned an old one, so that i could populate it with the data outside.
But it looks kind of ugly. I'm sure there must be something more elegant than that, i just couldn't find it. Please, help me if you can.
Your basically on the right path. Core Data is an object graph. There not a lot of dynamic built in. There's also no "upsert". like you surmise, you have to fetch and if it doesn't exist, you insert one.
Here is what I have just started using to handle a fetch-or-create scenario. I am using a top level managed object which contains a few to-many relationships to subordinate objects. I have a class that houses a few arrays of data (those are not shown here). This class is responsible for saving and retrieving to and from core data. When the class is created, I do a fetch-or-create to access my top level NSManagedObject.
#implementation MyDataManagerClass
...
#synthesize MyRootDataMO;
- (MyDataManagerClass *) init {
// Init managed object
NSManagedObjectContext *managedObjectContext = [(MyAppDelegate *)[[UIApplication sharedApplication] delegate] managedObjectContext];
// Fetch or Create root user data managed object
NSEntityDescription *entityDescription = [NSEntityDescription entityForName:#"MyRootDataMO" inManagedObjectContext:managedObjectContext];
NSFetchRequest *request = [[[NSFetchRequest alloc] init] autorelease];
[request setEntity:entityDescription];
NSError *error = nil;
NSArray *result = [managedObjectContext executeFetchRequest:request error:&error];
if (result == nil) {
NSLog(#"fetch result = nil");
// Handle the error here
} else {
if([result count] > 0) {
NSLog(#"fetch saved MO");
MyRootDataMO = (MyRootDataMO *)[result objectAtIndex:0];
} else {
NSLog(#"create new MO");
MyRootDataMO = (MyRootDataMO *)[NSEntityDescription insertNewObjectForEntityForName:#"MyRootDataMO" inManagedObjectContext:managedObjectContext];
}
}
return self;
}
...

String value cannot assigned to a string variable in iphone?

In my application, I take a UITextField value and trim it and assign to a string Variable declared in an Appdelegate. It assigns to a appdelegate variable and works well, sometimes It does not assign to the appdelegate variable.(This value is used in another view,so declared in appdelegate). Plz help...
NSString *txtTemp=[NSString stringWithFormat:#"%#",[txtName.text stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]];
txtName.text=txtTemp;
[self appDelegate].customSearchQuery=[NSString stringWithFormat:#"%#",txtTemp];
NSLog(#"--appDelegate.customSearchQuery =%#",appDelegate.customSearchQuery);
This is most probably a memory management problem.
NSString creates an autoreleased object. You will have to retain it if you want to use it outside the method you showed above. The easiest thing is to delcare as
#property (nonatomic, retain) NSString *customSearchQuery;
in your Appdelegate.h. That should do the trick.
In the dealloc-method of the appdelegate, you'll need to release it - otherwise you leak the NSString; with the declaration above, you'll add
customSearchQuery = nil;

Invalid receiver type 'NSUInteger'

I have a Core Data entity whose header file looks like this:
#interface MyEntity : NSManagedObject
{
}
#property (nonatomic, retain) NSNumber * index;
#end
And it's implementation file looks like this:
#implementation MyEntity
#dynamic index;
#end
Now, I have a piece of code that looks like this:
NSArray* selectedObects = [myEntityArrayController selectedObjects];
NSUInteger theIndex = [[[selectedObects objectAtIndex:0] index] unsignedIntegerValue];
The 'myEntityArrayController' object is a NSArrayController which manages all entities of MyEntity. This code executes correctly, however XCode always gives the warning "Invalid receiver type 'NSUInteger'" for the last line of code. For some reason, XCode thinks that the index method returns a NSUInteger. I'm not sure why it thinks this, because 'objectAtIndex' returns an object of type 'id'.
I've cleaned the project several times, and these warnings have hung around for a while. Any suggestions are appreciated.
Unroll your code so that each message is on its own line and then walk through it with the debugger to make sure every object is what you think it is.

Resources