Once again, since Core Data is new to me, I need assistance. Basically, I need to edit a specific Core Data object from a view outside the tableview, save it, and reload the tableview. I can manage reloading the tableview, but I cannot figure out how to find the specific Core Data object for that indexPath entry. I don't have any code because I cannot find anything to suit my purpose.
Detail (Editor)
-(IBAction)cancel:(id)sender{
NSLog(#"Sent!");
// [self dismissViewControllerAnimated:YES completion:nil];
// [self.view.superview removeFromSuperview];
OweDetails *details = info.details;
[info setValue:oField.text forKey:#"name"];
info.name = oField.text;
[UIView animateWithDuration:0.5
delay:1.0
options: UIViewAnimationOptionCurveEaseIn
animations:^{
self.master = [[MasterViewController alloc]init];
[self dismissSemiModalViewController:self];
[self.master.tableView reloadData];
}
completion:^(BOOL finished){
NSLog(#"Done!");
}];
}
Master (TableView)
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
NSLog(#"I tapped myself!");
OweInfo *info = [_fetchedResultsController objectAtIndexPath:indexPath];
self.tdModal = [[TDSemiModalViewController alloc]init];
[tableView deselectRowAtIndexPath:indexPath animated:YES];
FooterViewController *fvc = [[FooterViewController alloc]init];
OweDetails *details = info.details;
[self.tdModal setDetailItem:info.name];
[self.tdModal setMoneyItem:details.money];
// [self.view addSubview:test.view];
self.tdModal.managedObjectContext = self.managedObjectContext;
self.tdModal.managedObjectContext = self.managedObjectContext;
OweInfo *info2 = (OweInfo *)[nameArray objectAtIndex:indexPath.row];
self.tdModal.info = info2;
[self presentSemiModalViewController:self.tdModal];
}
If you're using an NSFetchedResultsController, ask it for the objectAtIndexPath:.
AppDelegate* appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
NSManagedObjectContext* context = [appDelegate managedObjectContext];
NSEntityDescription *entity = [NSEntityDescription
entityForName:#"YOUR_ENTITY_NAME" inManagedObjectContext:context];
[fetchRequest setEntity:entity];
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"SOME_PREDICATE_USED_TO_UNIQUELY_IDENTIFY_YOUR_INDEXPATH ==%#", #"VALUE"];
[fetchRequest setPredicate:predicate];
NSFetchRequest *request = [[NSFetchRequest alloc] init];
[request setEntity:entity];
[request setPredicate:predicate];
NSError* error;
NSArray* array = [context executeFetchRequest:request error:&error];
if (error)
{
NSLog(#"Error fetching data. %#", error);
return nil;
}
if (array.count != 1)
{
NSLog(#"Invalid number (%d) of objects found", array.count);
return nil;
}
return [array objectAtIndex:0];
Edit: This is in response to you asking about more details.
The code above can be its own function. I will give you a simple example of how you can use it.
-- In the VC where you have the table and are displaying the data
1: Let us assume your entity is called MyEntity and that it has an integer unique identifier field called myEntityUniqueId.
2: In your cellForRowAtIndexPath, you would write:
cell.tag = myCurrentEntity.myEntityUniqueId
-- Now lets go to your other VC where you want to retrieve the instance of MyEntity represented by the cell that was tapped.
1: Write the function:
-(void) findMyEntityForId:(int) tappedUniqueId
{
AppDelegate* appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
NSManagedObjectContext* context = [appDelegate managedObjectContext];
NSEntityDescription *entity = [NSEntityDescription
entityForName:#"MyEntity" inManagedObjectContext:context];
[fetchRequest setEntity:entity];
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"myEntityUniqueId ==%d", tappedUniqueId];
[fetchRequest setPredicate:predicate];
NSFetchRequest *request = [[NSFetchRequest alloc] init];
[request setEntity:entity];
[request setPredicate:predicate];
NSError* error;
NSArray* array = [context executeFetchRequest:request error:&error];
if (error)
{
NSLog(#"Error fetching data. %#", error);
return;
}
if (array.count != 1)
{
NSLog(#"Invalid number (%d) of objects found", array.count);
return;
}
MyEntity* foundResult = [array objectAtIndex:0]; // <-- This is the instance you are looking for.
}
2: Now call the above function with the correct argument.
I haven't tested the code but it should be fine.
Related
I am Using core data as my data base. Inside my UITableView I have a button to add projects , But at this moment I only Use it to add names. But the names I add do not display on the tableview.
I think my problem is that I need to repopulate my projectArray, how and where do I do that.
Here is my code:
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return [_projectArray count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
Project* project = _projectArray[indexPath.row];
static NSString *cellID = #"TableCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellID forIndexPath:indexPath];
cell.textLabel.text = project.name;
cell.detailTextLabel.text = #"prooo";
self.tableView.delegate = self;
self.tableView.dataSource = self;
return cell;
}
Here is my button code:
- (IBAction)addProjectButton:(id)sender {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Enter new project name."
message:nil
delegate:self
cancelButtonTitle:#"Cancel"
otherButtonTitles:#"Ok", nil];
alert.alertViewStyle = UIAlertViewStylePlainTextInput;
[alert show];
UITextField *textField = [alert textFieldAtIndex:0];
textField.placeholder = #"Project Name";
}
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex {
if (buttonIndex != alertView.cancelButtonIndex) {
UITextField *field = [alertView textFieldAtIndex:0];
AppDelegate *delegate = [UIApplication sharedApplication].delegate;
NSManagedObjectContext *context = [delegate managedObjectContext];
NSManagedObject *object =[NSEntityDescription insertNewObjectForEntityForName:#"Project" inManagedObjectContext:context];
[object setValue:field.text forKey:#"name"];
NSError *error;
[context save:&error];
if (![context save:&error]) {
NSLog(#"Whoops %# %#", error, [error localizedDescription]);
}
[self.tableView reloadData];
} else {
NSLog(#"cancel");
}
}
And here is my ViewWillAppear Code , where I fetch info:
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:nil];
AppDelegate *delegate = [UIApplication sharedApplication].delegate;
NSManagedObjectContext *context = [delegate managedObjectContext];
//load project
NSFetchRequest *fetch = [[NSFetchRequest alloc]init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Project" inManagedObjectContext:context];
[fetch setEntity:entity];
NSError *error;
_projectArray = [context executeFetchRequest:fetch error:&error];
}
There are many things you can do. To make it a good code, I will suggest write a method that reloads your array. Like this
-(void) reloadArray
{
AppDelegate *delegate = [UIApplication sharedApplication].delegate;
NSManagedObjectContext *context = [delegate managedObjectContext];
//load project
NSFetchRequest *fetch = [[NSFetchRequest alloc]init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Project" inManagedObjectContext:context];
[fetch setEntity:entity];
NSError *error;
_projectArray = [context executeFetchRequest:fetch error:&error];
}
Then replace your viewDidAppear like this -
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:nil];
[self reloadArray];
}
Also in your numberOfSectionsInTableView: method, make this change -
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
[self reloadArray];
return 1;
}
And it should do the magic...
Have you set the dataSource and delegate properties of tableView?
self.tableView.delegate = self;
self.tableView.dataSource = self;
Change This :
NSFetchRequest *fetch = [[NSFetchRequest alloc]init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Project" inManagedObjectContext:context];
[fetch setEntity:entity];
NSError *error;
_projectArray = [context executeFetchRequest:fetch error:&error];
To:
_projectArray = [[NSMutableArray alloc]init];
NSFetchRequest *fetch = [[NSFetchRequest alloc]init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Project" inManagedObjectContext:context];
[fetch setEntity:entity];
NSManagedObject *object = nil;
NSError *error;
NSArray *result = [context executeFetchRequest:fetch error:&error];
for (int i = 0; i < [result count]; i ++) {
object = [result objectAtIndex:i];
[_projectArray setObject:[object valueForKey:#"name"]
}
I am using a Core Data to save a UIImage that i get from my UIImagePickerController (source type = image library). I then Place or rather want to place the photo in a UICollectionViewCell, Please help and check to see what I am doing wrong.
Here is my UIImagePickerController it is called by a delegate.
-(void)requestAddScreen {
_picker = [[UIImagePickerController alloc] init];
_picker.delegate = self;
_picker.allowsEditing = NO;
_picker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
[self presentViewController:_picker animated:YES completion:nil];
}
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingImage:(UIImage *)image editingInfo:(NSDictionary *)editingInfo
{
AppDelegate *delegate = [UIApplication sharedApplication].delegate;
NSManagedObjectContext *context = [delegate managedObjectContext];
NSEntityDescription* entityDescription = [NSEntityDescription entityForName:#"Screen" inManagedObjectContext:context];
Screen* newScreen = [[Screen alloc] initWithEntity:entityDescription insertIntoManagedObjectContext:context];
NSData *imageData = UIImagePNGRepresentation(image);
newScreen.image = imageData;
[_project addProjectScreensObject:newScreen];
NSError *error;
[context save:&error];
if (![context save:&error]) {
NSLog(#"Whoops %# %#", error, [error localizedDescription]);
}
[self dismissViewControllerAnimated:_picker completion:^{
[_collectionView reloadData];
}];
}
And Here is my ViewWillAppear meted. this is where I fetch the data from Core Data, id it Correct?
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:nil];
AppDelegate *delegate = [UIApplication sharedApplication].delegate;
NSManagedObjectContext *context = [delegate managedObjectContext];
//load project
NSFetchRequest *fetch = [[NSFetchRequest alloc]init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Project" inManagedObjectContext:context];
[fetch setEntity:entity];
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"name == %#", #"EMO-KIT"];
[fetch setPredicate:predicate];
NSError *error;
NSArray *array = [context executeFetchRequest:fetch error:&error];
if (array.count == 1) {
_project = array[0];
} else {
_project = [NSEntityDescription insertNewObjectForEntityForName:#"Project" inManagedObjectContext:context];
[_project setValue:#"EMO-KIT" forKey:#"name"];
}
NSArray* screens = [[_project projectScreens] array];
NSIndexPath *bottomIndexPath=[NSIndexPath indexPathForRow:screens.count inSection:0];
[self.collectionView scrollToItemAtIndexPath: bottomIndexPath atScrollPosition:UICollectionViewScrollPositionRight animated:YES];
}
You can convert UIImage to NSData and save into Core Data as below
Saving
NSData * imageData = UIImagePNGRepresentation(image);
[newsObj setValue:imageData forKey:#"Image"];
Retrieving
UIImage *image = [UIImage imageWithData:[screenObj valueForKey:#"Image"]];
Hope it helps you..
I have 2 entities. 1 called WishListElement and other WishListContainer.
-(BOOL)addElementToWishList:(WishListElement*)element
{
ASAppDelegate* appDelegate = [UIApplication sharedApplication].delegate;
_managedObjectContext = [appDelegate managedObjectContext];
WishListElement *wishList = [NSEntityDescription insertNewObjectForEntityForName:#"WishListElement" inManagedObjectContext:_managedObjectContext];
[wishList setAppName: element.appName];
[wishList setAppPrice: element.appPrice];
[wishList setAppCategory: element.appCategory];
[wishList setAppSummary: element.appSummary];
[wishList setAppCopyright:element.appCopyright];
[wishList setAppAuthor: element.appAuthor];
[wishList setAppImage:element.appImage];
NSError *error = nil;
[_managedObjectContext save:&error];
WishListContainer *wishListContainer = [NSEntityDescription insertNewObjectForEntityForName:#"WishListContainer" inManagedObjectContext:_managedObjectContext];
[wishListContainer addContainsObject:wishList];
if (![_managedObjectContext save:&error])
{
return NO;
}
else
{
return YES;
}
}
-(NSMutableArray*)getWishListElement
{
ASAppDelegate *appDelegate = (ASAppDelegate*) [[UIApplication sharedApplication]delegate];
_managedObjectContext = [appDelegate managedObjectContext];
NSFetchRequest *request = [[NSFetchRequest alloc]init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"WishListContainer" inManagedObjectContext:_managedObjectContext];
[request setEntity:entity];
NSError *error = nil;
NSMutableArray *fetchRequest = [[_managedObjectContext executeFetchRequest:request error:&error]mutableCopy];
[self setWishListArray:fetchRequest];
WishListContainer *container = [fetchRequest objectAtIndex:0];
NSLog(#"%d",container.contains.count);
return [container.contains.allObjects mutableCopy];
}
But the problem is that when I try to display the wishlist contents using the above code, it shows an empty table view.
WishListContainer *container = [fetchRequest objectAtIndex:0];
NSLog(#"%d",container.contains.count);
return [container.contains.allObjects mutableCopy];
The above lines are showing 0. Please help me.
First of all, create an inverse relationship. As explained here https://stackoverflow.com/a/764572/3429577 it is necessary for data integrity.
I have a to-many relationship between 2 entities. Athlete(evals)<-->>Eval(whosEval). I am trying to display only the evals of the athlete who was selected. However, when I try to access the relationship through eval.whosEval, I get an undefined error. When I run the app, the table is empty, whereas if I comment out the predicate, it displays ALL Evals for ALL the Athletes. Am I missing something? Thank you.
allEvals.m
-(void)viewWillAppear:(BOOL)animated{
self.title = [NSString stringWithFormat:#"%#'s Evaluations",_athletesFullName];
AppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
_managedObjectContext = [appDelegate managedObjectContext];
NSFetchRequest *request = [[NSFetchRequest alloc] init];
NSFetchRequest *athleteRequest = [[NSFetchRequest alloc] init];
[athleteRequest setEntity:[NSEntityDescription entityForName:#"Athlete" inManagedObjectContext:_managedObjectContext]];
NSError *athleteError = nil;
NSArray *results = [_managedObjectContext executeFetchRequest:athleteRequest error:&athleteError];
NSPredicate *athletePredicate = [NSPredicate predicateWithFormat:#"full == %#", _athletesFullName];
[request setPredicate:athletePredicate];
Athlete *currentAthlete = [results objectAtIndex:0];
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"whosEval == %#", currentAthlete];
[request setPredicate:predicate];
NSEntityDescription *eval = [NSEntityDescription entityForName:#"Eval" inManagedObjectContext:_managedObjectContext];
[request setEntity:eval];
NSSortDescriptor *sortDescriptor =
[[NSSortDescriptor alloc] initWithKey:#"date_recorded"
ascending:NO
selector:#selector(localizedCaseInsensitiveCompare:)];
NSArray *sortDescriptors = [[NSArray alloc]initWithObjects:sortDescriptor, nil];
[request setSortDescriptors:sortDescriptors];
NSError *error = nil;
NSMutableArray *mutableFetchResults = [[_managedObjectContext executeFetchRequest:request error:&error] mutableCopy];
if (mutableFetchResults == nil){
//handle error
}
[self setEvalArray:mutableFetchResults];
[self.tableView reloadData];
NSLog(#"Athlete's Full Name is: %#",_athletesFullName);
}
Your predicate uses the athlete name when it should really use the athlete object:
#"whosEval == %#", self.athlete
You call
NSLog(#"This eval is for: %#", eval.whosEval);
But you declared eval as:
NSEntityDescription *eval = ...
So there is no way that class NSEntityDescription know what "whosEval" is.
Retrieve actual instance of Eval object from the mutableFetchResults and invoke whosEval on it:
if (mutableFetchResults == nil){
//handle error
} else {
[self setEvalArray:mutableFetchResults];
[self.tableView reloadData];
NSLog(#"Athlete's Full Name is: %#",_athletesFullName);
NSLog(#"This eval is for: %#", [[mutableFetchResults lastObject] whosEval]);
}
How do I edit the value of some field in CoreData entity (SQLite) by tapping to Button?
For example, in my UITableViewCell I have button. I would like this button to change the value of some boolean field. By tapping first time I would like to write YES and second time - NO.
1.Join is a manually created join table Ingredients<->>Join<<->Recipes
2._ingredientInfo contain only 1 record
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"cellIngredient";
IngredientCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[IngredientCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
// Configure the cell...
Ingredients *ingredient = [ingredientsArray_ objectAtIndex:indexPath.row];
cell.nameLabel.text = ingredient.name;
//Указываем что-то типа DataSource
AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
NSManagedObjectContext *context = appDelegate.managedObjectContext;
if (context != nil) {
NSFetchRequest *request = [[NSFetchRequest alloc] init];
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"inRecipe == %# AND ingredient == %#", self.recipe, ingredient];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Join" inManagedObjectContext:context];
[request setEntity:entity];
[request setPredicate:predicate];
NSError *error = nil;
NSMutableArray *mutableFetchResult = [[context executeFetchRequest:request error:&error] mutableCopy];
if (mutableFetchResult == nil) {
NSLog(#"No fetched objects!!!");
abort();
}
_ingredientInfo = [mutableFetchResult objectAtIndex:0];
}
cell.countLabel.text = [NSString stringWithFormat:#"%#", _ingredientInfo.count];
if (_ingredientInfo.inCart == [NSNumber numberWithInt:0]) {
cell.toCartBtn.imageView.image = [UIImage imageNamed:#"runTo.png"];
}
else {
cell.toCartBtn.imageView.image = [UIImage imageNamed:#"inCart.png"];
}
cell.unitLabel.text = ingredient.units;
return cell;
}
and when I tap the button cell.toCartBtn
- (IBAction)toCart:(id)sender
{
if (_ingredientInfo.inCart == [NSNumber numberWithInt:0]) {
_ingredientInfo.inCart = [NSNumber numberWithInt:1];
}
else {
_ingredientInfo.inCart = [NSNumber numberWithInt:0];
}
NSError *error = nil;
AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
if ([appDelegate.managedObjectContext save:&error]) {
[self.ingredientsTableView reloadData];
}
else {
NSLog(#"Error updating");
}
}
First fetch your object to be modified
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"entityName" inManagedObjectContext:managedObjectContext];
[fetchRequest setEntity:entity];
[fetchRequest setPredicate:[NSPredicate predicateWithFormat:#"(id == %#)", eID]];
NSError *error;
NSArray *details = [managedObjectContext executeFetchRequest:fetchRequest error:&error];
entityName *objEntity= nil;
//error handling goes here
if([details count] > 0)
objEntity = (entityName *)[details objectAtIndex:0];
Now update that entity as you insert it
if(objEntity){
club.fieldName = #"YES";
NSError *error = nil;
if(![self.managedObjectContext save:&error])
NSLog(#"Error updating");
}