I am trying to delete the data in a cell from the detailedViewController. I am trying to delete both an image and a video from the cell. For the video, I am saving both the url and the video data to core data, but I am only saving the url to the cell. Is there a way to delete a video based on a url (like deleteDataWithURL)? Here is the code I am using:
- (void) deleteVideAndImage {
NSManagedObject *objectToBeDeleted = [self managedObject]; // Replace this with whatever you use to reference the managed object
NSManagedObjectContext *context = [objectToBeDeleted managedObjectContext];
[context deleteObject:objectToBeDeleted];
[self.navigationController popViewControllerAnimated:YES];
}
That is not going to do anything to your table view. Deleting from Core Data will delete it from your Model but it will not change your View unless you have the two connected. If you want something removed from a View you should look at the Controller not the Model.
Related
I want my app to check the core data store at start-up. If the store is empty, it will add two items into it. What is the best way to implement this?
Can I put the following code in viewDidLoad?
- (void)viewDidLoad
{
[super viewDidLoad];
NSManagedObjectContext *managedObjectContext = [self managedObjectContext];
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] initWithEntityName:#"MonitorItem"];
self.monitorItemArray = [[managedObjectContext
executeFetchRequest:fetchRequest
error:nil] mutableCopy];
// If the core data is empty, populate it with the two compulsory items
if ([self.monitorItemArray count] == 0)
{
self.AddMandatoryItems;
}
[self.tableView reloadData];
}
I have searched other articles but none seems to give me an answer that I could understand.
Getting information from managedObjectContext in viewDidLoad is good.
If in cellForRowAtIndexPath you populate the cells from self.monitorItemArray than there is no reason to call reloadData (Which essentially erase the entire table view and re-draw it from scratch - which is exactly what happens when the view is appearing on screen any way...).
If you also show information from a web service, you can call reloadData in the response method to replace the existing data with the one that came from the web. Otherwise - if only information from core data is shown on the table view - no need for reloadData (Or maybe only in a case where the information in your managedObjectContext has changed while the table view is on screen).
I have a Table View in Xcode that is being populated by information that the user of the application is saving to iCloud. So my problem here is that whenever the user does save their data the data that is saved is being added to the every bottom of the table view of data instead of at the top which is where I want it to be seen once it has been saved.The data that is being saved is being saved to an array which then populates the Table View, but I am not sure how to sort the array due to the fact new data is being added to it every so often. Here is the code for the array in which i am working with:
- (NSArray *)notes
{
if (_notes) {
return _notes;
}
_notes = [[[NSUbiquitousKeyValueStore defaultStore] arrayForKey:#"AVAILABLE_NOTES"] mutableCopy];
if (!_notes) _notes = [NSMutableArray array];
return _notes;
}
and the data is being saved by this action here:
- (IBAction)save:(id)sender {
// Notify the previouse view to save the changes locally
[[NSNotificationCenter defaultCenter] postNotificationName:#"New Note" object:self userInfo:[NSDictionary dictionaryWithObject:self.finalScore.text forKey:#"Note"]];
[self dismissViewControllerAnimated:YES completion:nil];
}
Thanks!
You can store an object to the array that includes a date/time (along with your note data) - you can then sort the array by that value to get them in created order or reverse created order.
The other option might be since items are always added at the end, simply read the array in reverse order when displaying in the table. This may be helpful:
https://developer.apple.com/library/mac/documentation/Cocoa/Reference/Foundation/Classes/NSArray_Class/NSArray.html#//apple_ref/occ/instm/NSArray/reverseObjectEnumerator
In fact, look at all the methods on NSArray - some really good and useful stuff there.
Hope this helps.
I am trying to delete an image and a string from core data. I have a UITableView and when you click on a cell, it takes you to a deletedViewController there is a button to delete the items in the cell from core data as well as delete the cell from the table view.
Here is the code I am using:
//Delete Photo
NSManagedObject *objectToBeDeleted = [self managedObject]; // Replace this with whatever you use to reference the managed object
NSManagedObjectContext *context = [objectToBeDeleted managedObjectContext];
[context deleteObject:objectToBeDeleted];
[self.navigationController popViewControllerAnimated:YES];
Are you using fetchresultcontroller? The deletion will be performed finally when you call
[context save:&error];
And the fetchresultcontroller delegate will be called after this save to update the table view cells.
Code looks fine..
I will suggest if you use breakpoint to check the managedObject you are sending to deleteViewController is same as one you are deleting.
i'm doing some testing of Core Data, let's say i have a mainViewController with a navigationBar and addButton.
Clicking on the addButton will open a detailViewController. When i press save to insert a new Object the detailVieController will close and show the table with the new data inserted.
I can think two different way to do that.
FIRST METHOD - Passing the ManagedObjectContext
In the action of the add button i create an instance of the new detailViewController and i pass the managedObjectContext to it. So will be the save button of the detailViewController that will take care of saving the context and then pop the controller.
This is the method called by the addButton in the MainViewController
-(void)addNewObject{
DetailViewController *detVC = [DetailViewController alloc]initWhit:self.managedObjectCOntext];
[self.navigationcontroller pushViewController:detVC animated:YES];
}
This method is called by the save button in the IngredientViewController
-(void)saveObject{
NSError *error;
if (![self.managedObjectContext save:&error]){
NSLog(#"Error");
}
}
SECOND METHOD - Using a delegate
In the action of addButton i create an instance of DetailViewController, i set it as delegate, so when i press the save button in the DetailViewCOntroller will call the delegate that will pass data to the main controller.
This is the method called by the addButton in the MainViewController
(void)addNewObject{
DetailViewController *detVC = [DetailViewController alloc]init];
detVC.delegate = self;
[self.navigationcontroller pushViewController:detVC animated:YES];
}
This method is called by the save button in the IngredientViewController
-(void)saveObject{
[self.delegate detailVCdidSaveObject];
}
This is the delegate implemented in the mainViewController
detailVCdidSaveObject{
NSError *error;
if (![self.managedObjectContext save:&error]){
NSLog(#"Error");
}
}
------------------------------ Passing the object
Is it best to pass raw data to the DetailViewController and create there the object or it's best to pass the instance of the object to DetailViewController that will take care of settin its data?
For Example
This way i link the object instance of the mainVC to the one DetailVC so i can easilly set its value
-(void)addObject{
DetailViewController *detailVC =[[DetailViewController alloc]init];
detailVC.delegate = self;
self.object = [NSEntityDescription insertNewObjectForEntityForName:#"Object" inManagedObjectContext:self.managedObjectContext];
detailVC.object = self.object;
[self.navigationController pushViewController:detailVC animated:YES];
}
this way i pass raw data and let the detailVC create the instance
-(void)addObject{
DetailViewController *detailVC =[[DetailViewController alloc]initWithName:#"objname"];
[self.navigationController pushViewController:detailVC animated:YES];
}
those code are just pseudocode for educational purpose. all ways works, i just want to know which do you think it's the most correct and why. thanks
I have used the first two methods and in my opinion they are both equally valid (though I personally prefer delegation). However, the third method caused problems if you give the user the option to cancel or go back in a navigation controller. If that happens, you will have an object that you never needed to create.
This sounds like a perfect use case for a NSFetchedResultsController. A NSFetchedResultsController is an object makes displaying data from core data in a UITableView a lot easier. It even tells you when the objects in core data matching a predicate change (insert, delete, update, move).
So the way I would do it is that MainViewController would have a NSFetchedResultsController that provides the data to the UITableView. When you press the add button, it would do what you have in the first method. The DetailViewController will create the new instance, set the values on it then save the managedObjectContext.
Since the MainViewController has the NSFetchedResultsController, it will automatically know that a new object have been created and it can update the UITableView to show it.
The NSFetchedResutsController documentation and the NSFetchedResutsControllerDelegate documentation show you exactly how to use it with a UITableView including code you can copy into your view controller that do the majority of the work.
The actual answer depends on your preference. In my project, I have implemented the first two methods. A definite No for the third method from my side because of same reasons as Kevin mentioned. If the user cancels the operation or some error occurs, then you will have to take care of removing the change (Perhaps write the following code in your didMoveToParentViewController method and cancel method):-
[self.managedObjectContext rollback]
Assuming of course that you do not have any other process modifying that managedObjectContext at the same time.
Now, I prefer the first two methods because :-
The first method allows me to write additional code in saveObject method. Lets say that you want to validate some properties before saving the object. These properties are only present in detailViewController. So, you cannot use a delegate in that situation without explicitly passing each and every property back to delegate function (which can get messy).
Now, assume that you are creating a object in your mainViewController and the detailViewController is only used to populate a field of the object that was created in mainViewController. In such a situation, I would use the delegate method and pass the field back to the mainViewController so that when the user saves the object in mainViewController, then the field values are saved along with it. If the user cancels mainViewController, then the field values are also not saved.
From Xcode 4.2 Master-Detail template (for iPad) with Core Data, I modified the data model and added additional text view objects to the nib file.
Code for moving data from managed object to interface objects is in ConfigureView in DetailViewController and it's working fine.
I'm now trying to auto save the interface object data to managed object data when I move from one item to another in the popover.
I added the code for save in viewWillDisappear in DetailViewController, but this doesn't seem to fire. Am I missing something?
- (void)configureView { // Update the user interface for the detail item.
if (self.detailItem) {
self.sname.text = [self.detailItem valueForKey:#"sname"];
self.saddress.text = [self.detailItem valueForKey:#"saddress"];
}
}
- (void)viewWillDisappear:(BOOL)animated {
[self.detailItem setValue: self.sname.text forKey:#"sname"];
[self.detailItem setValue: self.saddress.text forKey:#"saddress"];
NSError *error; if (![self.detailItem.managedObjectContext save:&error]) {
NSLog(#"Unresolved error %#, %#",error,[error userInfo]);
exit(-1); //fail
}
[super viewWillDisappear:animated];
}
First, in a MasterDetail application the detailViewController is usually always be visible and not disappear. So that is why viewWillDisappear is not being called. Of course I'm not sure about the particulars of your app architecture, so I may be wrong.
Secondly, consider the use case if the user changes some data then switches to another application. Then while in the other application, the system terminates your app. The changes that your user made will be lost and will run counter to what they expect.
Unless you are saving a lot of data for the interface in detailViewController, consider saving the data after the user changes data in the interface rather than when the user switches from managedObject to managedObject in the popoverViewController. i.e. when the user edits some data in a textView or textfield, perform a save on the managedObjectContext.
Good Luck!