Adding to created Entities attributes using Magical Record - ios

so I am using Magical Record in my project, and I am attempting to do the following:
- (void)persistNewReadingWithOneA:(NSString *)oneA oneB:(NSString *)oneB{
NSManagedObjectContext *localContext = [NSManagedObjectContext MR_contextForCurrentThread];
FinalRead *reading1A = [FinalRead MR_createInContext:localContext];
reading1A.a1 = oneA;
reading1A.b1 = oneB;
[localContext MR_saveOnlySelfAndWait];
}
As you can see I've persisted with a new entry and now I need to be able to update that same entry by adding to it's attributes. I tried doing the following:
- (void)updateReadingWithTwoA:(NSString *)twoA twoB:(NSString *)twoB{
NSManagedObjectContext *localContext = [NSManagedObjectContext MR_contextForCurrentThread];
FinalRead *reading2A = [FinalRead MR_createInContext:localContext];
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"firstname ==[c] %# AND lastname ==[c] %#"];
FinalRead *finalRead = [FinalRead MR_findFirstWithPredicate:predicate inContext:localContext];
reading2A.a2 = twoA;
reading2A.b2 = twoB;
[localContext MR_saveOnlySelfAndWait];
}
Any Ideas?
EDIT:
I am fetching data from a JSON response like so:
- (void)fetchedData:(NSData *)responseData {
if (self.buttonPressed){
//parse out the json data
NSError* error;
NSArray* json = [NSJSONSerialization
JSONObjectWithData:responseData
options:kNilOptions
error:&error];
NSString *string = [NSString stringWithFormat:#"%#", [json objectAtIndex:0]];
[self persistNewReadingWithOneA:string
oneB:nil];
}else{
//parse out the json data
NSError* error;
NSArray* json = [NSJSONSerialization
JSONObjectWithData:responseData
options:kNilOptions
error:&error];
NSString *string = [NSString stringWithFormat:#"%#", [json objectAtIndex:0]];
[self persistNewReadingWithOneA:nil
oneB:string];
}
}
and then storing to a newly created object like so:
- (void)persistNewReadingWithOneA:(NSString *)oneA oneB:(NSString *)oneB{
NSManagedObjectContext *localContext = [NSManagedObjectContext MR_contextForCurrentThread];
FinalRead *reading1A = [FinalRead MR_createInContext:localContext];
reading1A.a1 = oneA;
reading1A.b1 = oneB;
[localContext MR_saveOnlySelfAndWait];
}
The ViewController then pushes to another that asks another question where once again more JSON is parsed and stored, but into the SAME object that was just created in the previous ViewController. I have the following attributes PER object in NSManagedObject:
#interface FinalRead : NSManagedObject
#property (nonatomic, retain) NSString *a1;
#property (nonatomic, retain) NSString *b1;
#property (nonatomic, retain) NSString *a2;
#property (nonatomic, retain) NSString *b2;
#property (nonatomic, retain) NSString *a3;
#property (nonatomic, retain) NSString *b3;
#property (nonatomic, retain) NSString *a4;
#property (nonatomic, retain) NSString *b4;
#end
So basically, every time that I change a new viewController I'm wanting to add to that same object until the final View has been used.

Your update method also creates a new object:
FinalRead *reading2A = [FinalRead MR_createInContext:localContext];
// ... other stuff
reading2A.a2 = twoA;
reading2A.b2 = twoB;
And the object fetched here:
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"firstname ==[c] %# AND lastname ==[c] %#"];
FinalRead *finalRead = [FinalRead MR_findFirstWithPredicate:predicate inContext:localContext];
is completely unused. In fact I would expect that fetch request to crash, because the
predicate uses %# formats for which no arguments are supplied.
To update an object, you have to fetch it first. And to fetch it you need some
attributes which identify the object that you want to update. For example:
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"firstname ==[c] %# AND lastname ==[c] %#",
firstName, lastName];
FinalRead *finalRead = [FinalRead MR_findFirstWithPredicate:predicate inContext:localContext];
if (finalRead) {
finalRead.a2 = twoA;
finalRead.b2 = twoB;
// ... save context ...
} else {
// no matching object found
}
Update: The solution in your case might be to pass the finalRead object from one
view controller to the next, instead of re-fetching it in each view controller.

Related

IOS: NSKnownKeysDictionary1 error

I have an object selectedActivity defined as follows:
#property (strong, nonatomic) Activities *selectedActivity;
At the point I need to work with it logs out as:
{
actname = "Running";
aid = 23;
}
The Activities object is an NSManaged object and its .h file looks like this.
#interface Activities : NSManagedObject
#property (nonatomic, retain) NSString * actname;
#property (nonatomic, retain) NSNumber * aid;
#end
I am trying to place one of the object properties in a variable to work with it using the following:
NSNumber *aid = _selectedActivity.aid;
However, the above line gives the following error message:
[NSKnownKeysDictionary1 aid]: unrecognized selector sent to instance 0x147842fb0
Can anyone explain this error and how to fix it?
Thanks for any suggestions.
Update:
setting of selected activity
-(void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component {
_selectedActivity =([_activities objectAtIndex:row]);
NSLog(#"selectedActivity in pickerview%#",_selectedActivity);
}
//activities in .h file
#property (strong, nonatomic) NSArray *activities;
//setting of activities
self.activities= [self getActivities];
//method that gets activities
- (id) getActivities{
NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:#"Activities"];
NSSortDescriptor *sort = [NSSortDescriptor sortDescriptorWithKey:#"created" ascending:NO];
[fetchRequest setSortDescriptors:#[sort]];
NSError *error = nil;
self.managedObjectContext = [Model sharedInstance].managedObjectContext;
NSArray *results = [self.managedObjectContext executeFetchRequest:fetchRequest
error:&error];
NSMutableArray *mutableresults = [results mutableCopy];
[mutableresults removeObjectIdenticalTo:[NSNull null]];
return mutableresults;
}
The results are coming as a dictionary.
instead of the usual NSManagedObject-style value retrieval:
Objective-C
NSString *actname = _selectedActivity.actname;
NSNumber *aid = _selectedActivity.aid;
Swift
let actname:String = _selectedActivity.actname
let aid:Int = _selectedActivity.aid
Use the NSDictionary-style value retrieval, like so:
Objective-C:
NSString *actname = [_selectedActivity valueForKey:#"actname"];
NSNumber *aid = [[_selectedActivity valueForKey:#"aid"] intValue];
Swift (tested as of 3.0.1)
_selectedActivity(forKey: "actname") as! String
_selectedActivity.value(forKey: "aid") as! Int

How to save NSArray data in coredata?

I want to save my data in coredata from NSArray. How can I achieve this ?
NSArray *fetchdata = [Lockbox arrayForKey:#"fetch"];
Here, I am getting data in below form:
How can I save this data in NSManageobject?
Here is my try:
NSFetchRequest *fetchrequestforside=[NSFetchRequest fetchRequestWithEntityName:#"demo"];
NSManagedObjectContext *context = [self managedObjectContext];
NSManagedObject *newDevice1 = [NSEntityDescription
insertNewObjectForEntityForName:#"demo"
inManagedObjectContext:context];
NSArray *fetchdata = [Lockbox arrayForKey:#"fetch"]; //
for (int i =0;i<[fetchdata count];i++){
NSString *Name = [[fetchdata objectAtIndex:i] objectForKey:#"name"];
NSString *Websitename = [[fetchdata objectAtIndex:i] objectForKey:#"websitename"];
NSString *Feedlink = [[fetchdata objectAtIndex:i] objectForKey:#"feedurl"];
NSLog(#"value:%#,%#,%#",Name,Websitename,Feedlink);
[newDevice1 setValue:Name forKey:#"name"];
[newDevice1 setValue:Websitename forKey:#"websitename"];
[newDevice1 setValue:Feedlink forKey:#"feedurl"];
NSLog(#"value:%#,%#,%#",Name,Websitename,Feedlink);
// Save the context.
NSError *error = nil;
if (![context save:&error]) {
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
abort();
}
}
But with this technique I am getting an error. How can I resolve this problem?
EDIT:-
I am getting this error:
*** Terminating app due to uncaught exception
'NSInvalidArgumentException', reason: '-[__NSCFString objectForKey:]:
unrecognized selector sent to instance 0x7ff262520660'
Your code treats the contents of the fetchdata array as instances of NSDictionary, but, LockBox only appears to support string contents:
-(NSArray *)arrayForKey:(NSString *)key
{
NSArray *array = nil;
NSString *components = [self objectForKey:key];
if (components)
array = [NSArray arrayWithArray:[components componentsSeparatedByString:kDelimiter]];
return array;
}
So, you need to deal with the conversion. You're probably part dealing with it already to store the original array...
But, that's why you get the error, the code expects a dictionary but actually gets a string
Do you have an object that looks like this?
#import <Foundation/Foundation.h>
#import <CoreData/CoreData.h>
#interface demo : NSManagedObject
#property (nonatomic, retain) NSString * name;
#property (nonatomic, retain) NSString * websitename;
#property (nonatomic, retain) NSString * feedurl;
#end
After creating an object like this (using insertNewObjectForEntityForName) try to fetch it like that:
NSFetchRequest *request = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:entityName inManagedObjectContext:self.managedObjectContext];
[request setEntity:entity];
NSArray *results = [self.managedObjectContext executeFetchRequest:request error:&error];
Btw, I would recommended you to stick to the naming conventions and call it Demo.
Cheers
I advice you to use the awesome library MagicalRecord
it save much time and very easy
here its tutorial
MagicalRecord Tutorial

Using of ALL/ANY/NONE in NSPredicate

I'm trying to understand NSPredicate and it's syntax, when we are using ALL/ANY etc
My class Person:
#interface Person : NSObject
#property (nonatomic, strong) NSString* name;
#property (nonatomic, strong) NSString* surname;
#property NSUInteger age;
#property NSUInteger weight;
#property NSUInteger height;
And I use it for predicates like this:
NSArray* persons = [NSArray arrayWithObjects:personOne, personTwo, personThree, personFour, nil];
My predicate:
NSPredicate* predicateEight = [NSPredicate predicateWithFormat:#"ANY SELF.age > %#", #55];
filteredArray = [persons filteredArrayUsingPredicate:predicateEight];
NSLog(#"Age > 55 %#", filteredArray);
And I've received a mistake:
The left hand side for an ALL or ANY operator must be either an
NSArray or an NSSet
How I need to change my code?
Thanks in advance for any help.
It should like this :
NSPredicate* predicateEight = [NSPredicate predicateWithFormat:#"self.age > %d", 55];
;)
ALL/ANY used for NSArray or NSSet. In your case ANY used for instance of Person.
Example of use ANY:
NSPredicate* predicateEight = [NSPredicate predicateWithFormat:#"ANY SELF.age > %#", #55];
BOOL result = [predicateEight evaluateWithObject:persons];
If you have Array of persons (Array of Arrays):
NSArray* group1 = [NSArray arrayWithObjects:personOne, personTwo, personThree, nil];
NSArray* group2 = [NSArray arrayWithObjects:personFour, personFive, personSix, nil];
NSArray* group3 = [NSArray arrayWithObjects:personSeven, personEight, personNine, nil];
NSArray* groups = [NSArray group1, group2, group3, nil];
NSPredicate* predicateEight = [NSPredicate predicateWithFormat:#"ANY SELF.age > %#", #55];
NSArray* filteredArray = [groups filteredArrayUsingPredicate:predicateEight];

Search NSArray of objects for String matching any property

I have an NSArray of objects, and those objects have 10 properties. I would like to do a text search of those objects.
I know how to search 1 property at a time, but is there an easy way to search ALL properties at once?
Here is a list of properties that my objects have:
#property (nonatomic, retain) NSString * name;
#property (nonatomic, retain) NSString * phone;
#property (nonatomic, retain) NSString * secondaryPhone;
#property (nonatomic, retain) NSString * address;
#property (nonatomic, retain) NSString * email;
#property (nonatomic, retain) NSString * url;
#property (nonatomic, retain) NSString * category;
#property (nonatomic, retain) NSString * specialty;
#property (nonatomic, retain) NSString * notes;
#property (nonatomic, retain) NSString * guid;
If I search for "doctor", I would like to see all results where 1 or more of these properties has the word "doctor" in it. For example, if 1 object has a category of "doctor", and another object has an email address of "smith#doctorsamerica.com", they should both show up in the results.
NSString *searchTerm = #"search this";
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"SELF LIKE[cd] %#", searchTerm];
NSArray *filtered = [array filteredArrayUsingPredicate:predicate];
If there is a specific property you can change the predicate to:
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"SELF.propertyName LIKE[cd] %#", searchTerm];
To search all properties, you will have to bind them together with a logical operator
NSString *query = #"blah";
NSPredicate *predicateName = [NSPredicate predicateWithFormat:#"name contains[cd] %#", query];
NSPredicate *predicatePhone = [NSPredicate predicateWithFormat:#"phone contains[cd] %#", query];
NSPredicate *predicateSecondaryPhone = [NSPredicate predicateWithFormat:#"secondaryPhone contains[cd] %#", query];
NSArray *subPredicates = [NSArray arrayWithObjects:predicateName, predicatePhone, predicateSecondaryPhone, nil];
NSCompoundPredicate *predicate = [NSCompoundPredicate orPredicateWithSubpredicates:subPredicates];
Add a matches: method to your class:
- (BOOL)matches:(NSString *)term {
if ([self.name rangeOfString:term options:NSCaseInsensitiveSearch| NSDiacriticInsensitiveSearch].location != NSNotFound) {
return YES;
} else if ([self.phone rangeOfString:term options:NSCaseInsensitiveSearch| NSDiacriticInsensitiveSearch].location != NSNotFound) {
return YES;
} else if (...) { // repeat for all of the properties
return YES;
}
return NO;
}
Now you can iterate over your objects checking each one:
NSArray *peopleArray = ... // the array of objects
NSString *someTerm = ... // the search term
NSMutableArray *matches = [NSMutableArray array];
for (id person in peopleArray) {
if ([person matches:someTerm]) {
[matches addObject:person];
}
}
Instead of hardcoding each property name individually, you could get an array of the class's property names: List of class properties in Objective-C, (assuming they were all strings, or you could check if each property's type is of class NSString but I'm not sure how to do this)
and then on each of the objects you'd like to search, you could iterate through each of the object's properties and inspect the value on each:
id objectValue = [object valueForKey:[NSString stringWithUTF8String:propertyName]];
// let's say the property is a string
NSString *objectValueString = (NSString *)objectValue;
Then you could check if the property matches your searchTerm with something like:
BOOL propertyValueMatchesSearchTerm = [objectValueString rangeOfString:mySearchTermString].location != NSNotFound;
if (propertyValueMatchesSearchTerm) {
// add object to search results array
}

Delete an object in core data

I have an entity in my core data model like this:
#interface Selection : NSManagedObject
#property (nonatomic, retain) NSString * book_id;
#property (nonatomic, retain) NSString * contenu;
#property (nonatomic, retain) NSNumber * page_id;
#property (nonatomic, retain) NSNumber * nbrOfOccurences;
#property (nonatomic, retain) NSString * next;
#property (nonatomic, retain) NSString * previous;
I have created many Selections and saved them in Core Data and now I would like to delete some selections with some criteria. For example, I would like to delete a Selection object if matches the following:
content = test
page_id = 5
book_id = 1331313
How I can do this?
What Mike Weller wrote is right. I'll expand the answer a little bit.
First you need to create a NSFetchRequest like the following:
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
[fetchRequest setEntity:[NSEntityDescription entityForName:#"Selection" inManagedObjectContext:context]];
Then you have to set the predicate for that request like the following:
[fetchRequest setPredicate:[NSPredicate predicateWithFormat:#"content == %# AND page_id == %# AND book_id == %#", contentVal, pageVal, bookVal]];
where
NSString* contentVal = #"test";
NSNumber* pageVal = [NSNumber numberWithInt:5];
NSString* bookVal = #"1331313";
I'm using %# since I'm supposing you are using objects and not scalar values.
Now you perform a fetch in the context with the previous request:
NSError* error = nil;
NSArray* results = [context executeFetchRequest:fetchRequest error:&error];
results contains all the managed objects that match that predicate.
Finally you could grab the objects and call a deletion on them.
[context deleteObject:currentObj];
Once done you need to save the context as per the documentation.
Just as a new object is not saved to the store until the context is saved, a deleted object is not removed from the store until the context is saved.
Hence
NSError* error = nil;
[context save:&error];
Note that save method returns a bool value. So you can use an approach like the following or display an alert to the user. Source NSManagedObjectContext save error.
NSError *error = nil;
if ([context save:&error] == NO) {
NSAssert(NO, #"Save should not fail\n%#", [error localizedDescription]);
abort();
}
You should perform a fetch request using an NSPredicate with the appropriate conditions, and then call the deleteObject: method on NSManagedObjectContext with each object in the result set.
In addition to Mike Weller and flexaddicted, after calling [context deleteObject:currentObj]; you need to save: context:
NSError *error = nil;
[context save:&error];
As from documentation:
Just as a new object is not saved to the store until the context is saved, a deleted object is not removed from the store until the context is saved.
That made matter in my case.

Resources