DetailViewController not showing when creates new object - uitableview

Quick question fellas...
The IBAction button is creating a New Object but when the navigator pushes the DetailViewController it's giving me SIGABRT.
Now I'm wondering if I just cannot use the navigation controller function there.
The following code is the one not working correctly
- (IBAction)insertNewObject
{
// Create a new instance of the entity managed by the fetched results controller.
NSManagedObjectContext *context = [self.fetchedResultsController managedObjectContext];
NSEntityDescription *entity = [[self.fetchedResultsController fetchRequest] entity];
Event *newEvent = [NSEntityDescription insertNewObjectForEntityForName:[entity name] inManagedObjectContext:context];
DetailViewController *detailController = [[[DetailViewController alloc] init] autorelease];
[newEvent setValue:[NSDate date] forKey:#"timeStamp"];
// Save the context with the new object.
NSError *error = nil;
if (![context save:&error]) {
//improve this
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
abort();
}
[detailController setEvent:newEvent];
NSLog(#"Detail Controller New Event 1 (from Master) : %#", newEvent);
[self.navigationController pushViewController:detailController animated:YES];
}
Now When I select the cell it works perfectly. So the below code works:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([[segue identifier] isEqualToString:#"selectSegue"]) {
NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];
Event *event = (Event *)[fetchedResultsController objectAtIndexPath:indexPath];
NSLog(#"Event on Master:: %#", event);
DetailViewController *detailvc = [[[DetailViewController alloc] init] autorelease];
detailvc.event = [self.fetchedResultsController objectAtIndexPath:indexPath];
NSLog(#"Event on Detail when created :: %#", detailvc.event);
if (event) [[segue destinationViewController] setEvent:(Event *) [self.fetchedResultsController objectAtIndexPath:indexPath]]; //was: setDetailItem:selectedObject
[event release];
[detailvc.event retain];
}
}
Feels like I'm missing something simple. But could anyone help me add the object to that DetailViewController without getting a SIGABRT ?
Thanks and Happy New Year everyone.

Your Code seems to be all fine.
For my Experience, you should check if you Set all Mandatory Attributes for the Entity. Because in some Cases the Error statement doesnt mind this error!

Related

Adding data to Core Data (using tableview), delete existing ones

I'm triing to add NSManagedObject to existing data, but right after i did, my existing data disappears, and i cannot figure out why. Looking the code for like an hour couldnt help much :(
FirstTableViewController.m //DELEGATE points to AppDelegate
- (void)viewDidLoad {
[super viewDidLoad];
self.context=[DELEGATE managedObjectContext];
self.everyWish=[[NSMutableArray alloc]initWithArray:[DELEGATE collectSharedWishes]]; //collects every shared wishes from core data
self.emberek=[[NSMutableArray alloc]initWithArray:[DELEGATE collectUserNames]]; //collects every user
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell=[tableView dequeueReusableCellWithIdentifier:IDENTIFIER forIndexPath:indexPath];
User *emberek=[self.emberek objectAtIndex:indexPath.row];
NSMutableArray *currentUserWishes=[[NSMutableArray alloc]initWithArray:[DELEGATE collectCurrentUserSharedWishes:emberek]]; //collects the current user wishes only from core data
int completed=0;
for(SharedWishes *wish in currentUserWishes)
if([wish.wishIsPurchased isEqual:#1])
completed++;
cell.textLabel.text=emberek.userName;
cell.detailTextLabel.text=[NSString stringWithFormat:#"Wishes: %lu, purchased: %d", (unsigned long)currentUserWishes.count, completed];
return cell;
}
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if([segue.identifier isEqualToString:#"pushToCurrentUser"]){
User *user=[self.emberek objectAtIndex:[[self.tableView indexPathForSelectedRow]row]];
SharedTableViewController *wishTVC=[segue destinationViewController];
wishTVC.user=user;
NSLog(#"%#", user);
}
}
OtherTableViewController.h
#property NSManagedObjectContext *context;
#property User *user;
OtherTableViewController.m
- (void)viewDidLoad
{
[super viewDidLoad];
self.context=[DELEGATE managedObjectContext];
self.format=[[NSDateFormatter alloc]init];
self.todayFormat=[[NSDateFormatter alloc]init];
self.results=[[NSMutableArray alloc]init];
self.wishes=[[NSMutableArray alloc]initWithArray:[DELEGATE collectCurrentUserSharedWishes:self.user]];
self.navigationItem.title=[NSString stringWithFormat:#"%#'s list", self.user.userName];
[[NSNotificationCenter defaultCenter]addObserver:self selector:#selector(refreshTableViewData) name:#"refreshTableViewData" object:nil];
self.refreshControl=[[UIRefreshControl alloc] init];
[self.refreshControl setTintColor:[UIColor redColor]];
[self.tableView addSubview:self.refreshControl];
[self.refreshControl addTarget:self action:#selector(pullDownToRefresh:) forControlEvents:UIControlEventValueChanged];
}
-(void)fetch:(CKRecord *)obj
{
NSError *error;
SharedWishes *wish=[NSEntityDescription insertNewObjectForEntityForName:#"SharedWishes" inManagedObjectContext:self.context];
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"SharedWishes" inManagedObjectContext:self.context];
[fetchRequest setEntity:entity];
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"wishID==%#", obj.recordID.recordName];
[fetchRequest setPredicate:predicate];
NSArray *fetchedObjects = [self.context executeFetchRequest:fetchRequest error:&error];
if (fetchedObjects == nil)
NSLog(#"Nem sikerult az ab-t elerni!, %#", [error localizedDescription]);
if([fetchedObjects isEqual:#[]])
{
User *currentUser=[[DELEGATE fetchUserWithID:self.user.userID] objectAtIndex:0]; //fetches the current user, which i already have, tried before using [self.user addSharedWishesObject:wish]
wish.wishName=obj[#"name"];
wish.wishPrice=obj[#"price"];
wish.wishIcon=obj[#"icon"];
wish.wishTime=obj[#"creationDate"];
wish.wishLocation=obj[#"location"];
wish.wishDescription=obj[#"description"];
wish.wishType=obj[#"type"];
wish.wishURL=obj[#"url"];
wish.wishImage=obj[#"image"];
wish.wishID=obj.recordID.recordName;
wish.wishIsPurchased=obj[#"purchased"];
wish.wishChangeTag=obj.recordChangeTag;
NSError *error;
[currentUser addSharedWishesObject:wish];
if(![self.context save:&error])
NSLog(#"Nem tudtam eltarolni az adatbazisban, oka: %#", [error localizedDescription]);
}
else
{
wish=[fetchedObjects objectAtIndex:0];
if(![wish.wishChangeTag isEqualToString:obj.recordChangeTag]){
wish.wishName=obj[#"name"];
wish.wishPrice=obj[#"price"];
wish.wishIcon=obj[#"icon"];
wish.wishTime=obj[#"creationDate"];
wish.wishLocation=obj[#"location"];
wish.wishDescription=obj[#"description"];
wish.wishType=obj[#"type"];
wish.wishURL=obj[#"url"];
wish.wishImage=obj[#"image"];
wish.wishID=obj.recordID.recordName;
wish.wishIsPurchased=obj[#"purchased"];
wish.wishChangeTag=obj.recordChangeTag;
//wish.user.userID=obj.creatorUserRecordID.recordName;
NSError *error;
if(![self.context save:&error])
NSLog(#"Nem tudtam eltarolni az adatbazisban, oka: %#", [error localizedDescription]);
}
}
}
Here is the code, it runs without an error, everything declared properly, although i didnt mention (in order to simplify my code).
After running, I have all the users, but only the last one's wishes appears, calling the NSMutableArray *currentUserWishes=[[NSMutableArray alloc]initWithArray:[DELEGATE collectCurrentUserSharedWishes:emberek]]; from FirsTableViewController. The last one has correct amount of objects, the previous ones have #"0 objects".
Saving them right in the OtherTableViewController? Any thoughts?
ps: posting more details if needed
BUG fixed:
Right after I saved the objects, I called a method, in which I compared my elelements (in my DB) to the cloud elements, and delete those which wasn't available any longer in the clouds from my persistent database. A "wrong" predicate caused the main issue because I queried all my database objects, instead of the particular user's elements

How to pass a custom property between view controller using NSManagedObject object?

I'm working on a simple notes app, and I created an entity called "Note" in the data model that have only one attribute that named "content" of type nsstring.
Now I careated a Note class using editor/create NSManagedObject subclass from the data model section.
In my create notes view controller i'm saving the data to the database in the prepareForSegue method that looks like this:
#implementation NOCreateNotesViewController
- (NSManagedObjectContext *) managedObjectContext
{
NSManagedObjectContext *context = nil;
id delegate = [[UIApplication sharedApplication] delegate];
if ([delegate performSelector:#selector(managedObjectContext)]) {
context = [delegate managedObjectContext];
}
return context;
}
- (void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if (sender != self.saveButton) return;
if (self.noteText.text.length > 0) {
self.note = [[Note alloc] init];
self.note.content = self.noteText.text;
}
NSManagedObjectContext * context = [self managedObjectContext];
// creating a new managed object
NSManagedObject *newNote = [NSEntityDescription insertNewObjectForEntityForName:#"Note" inManagedObjectContext:context];
[newNote setValue:self.noteText.text forKey:#"content"];
NSError * error = nil;
if ([context save:&error]) {
NSLog(#"Can't Save! %# %#", error, [error localizedDescription]);
}
}
But not I want to pass the object that a user wants to edit (meaning the note in the selected row from the table view) this way:
- (void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqualToString:#"editeNote"]) {
NSManagedObject * selectedNote = [self.notes objectAtIndex:[self.tableView indexPathForSelectedRow].row];
NOCreateNotesViewController * destination = [segue destinationViewController];
destination.note = selectedNote;
}
}
And obviously I can't pass a Note object with a pointer to NSManagedObject...this is because I want to update my Note entity if this is an editing segue instead of creating a new one.
In the tutorial I learned core data basics from they teach with just creating objects on the fly and note using a custom class for the objects with editor/create NSManagedObject subclass so i'm getting a bit confused..
Please help
NSManagedObject * selectedNote = [self.notes objectAtIndex:[self.tableView indexPathForSelectedRow].row];
wants to be:
Note * selectedNote = [self.notes objectAtIndex:[self.tableView indexPathForSelectedRow].row];
Why are you saving the data to your model in prepareForSegue:? Surely you have a Save or Done button in the view?

Update TableView after adding CoreData

I'm working on a CoreData App which displays the content of the CoreData in a TableView.
The Problem is, after adding a string the tableView is not Updating the Content of the CoreData.
i tried it with:
- (void)viewWillAppear:(BOOL)none
{
[self.tableView reloadData];
}
But no Chance, its not reloading.
Any guesses or should I post some more Code? thank you :)
So more Code :)
Saving string to CoreData:
- (void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
AppDelegate *appDelegate =
[[UIApplication sharedApplication] delegate];
NSManagedObjectContext *context =
[appDelegate managedObjectContext];
NSManagedObject *newProduct;
newProduct = [NSEntityDescription
insertNewObjectForEntityForName:#"Products"
inManagedObjectContext:context];
[newProduct setValue: _textField.text forKey:#"productName"];
NSError *error;
[context save:&error];
NSLog(#"Product saved");
}
And the Code of the TableViewController:
#implementation CartViewController
- (id)initWithStyle:(UITableViewStyle)style
{
self = [super initWithStyle:style];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
//Core Data Versuche
/*
Fetch existing events.
Create a fetch request for the Event entity; add a sort descriptor; then execute the fetch.
*/
NSFetchRequest *request = [[NSFetchRequest alloc] initWithEntityName:#"Products"];
[request setFetchBatchSize:20];
// Order the events by creation date, most recent first.
// NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"creationDate" ascending:NO];
// NSArray *sortDescriptors = #[sortDescriptor];
// [request setSortDescriptors:sortDescriptors];
// Execute the fetch.
NSError *error;
AppDelegate *delegate = (AppDelegate*)[[UIApplication sharedApplication] delegate];
NSArray *fetchResult = [delegate.managedObjectContext executeFetchRequest:request error:&error];
if (fetchResult== nil) {
// Replace this implementation with code to handle the error appropriately.
// abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
}
// Set self's events array to a mutable copy of the fetch results.
[self setCartProductsArray:[fetchResult mutableCopy]];
/*
Reload the table view if the locale changes -- look at APLEventTableViewCell.m to see how the table view cells are redisplayed.
*/
__weak UITableViewController *cell = self;
[[NSNotificationCenter defaultCenter] addObserverForName:NSCurrentLocaleDidChangeNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *note) {
[cell.tableView reloadData];
}];
// Ende Core Data Versuche
}
- (void)viewWillAppear:(BOOL)none
{
[self.tableView reloadData];
}
What you probably want to do is use an NSFetchedResultsController.
Make sure that when you are updating the data, you are really just updating CoreData.
When things change in CoreData and you have an NSFetchedResultsController you can subscribe to updates. Apple has great documentation on how to make this work. These updates will update your table correctly using the delegation methods. This ends up mostly being a copy and paste from the documentation.

How do I remove a single object in a cell of a UICollectionView?

I am using UICollectionView and with this method i can delete all objects that I have added to CoreData:
- (IBAction)btnDelete:(id)sender {
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:#"Are you sure?" message:#"Delete all favorites?" delegate:self cancelButtonTitle:#"Cancel" otherButtonTitles:#"OK", nil];
[alertView show];
}
- (void)alertView:(UIAlertView *)alertView willDismissWithButtonIndex:(NSInteger)buttonIndex {
if(buttonIndex == 0){
nil;
} else if (buttonIndex == 1){
AppDelegate *delegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
NSManagedObjectContext *context = [delegate managedObjectContext];
NSFetchRequest *execQuery =[[NSFetchRequest alloc] init];
NSEntityDescription *descOggetto = [NSEntityDescription entityForName:#"HexCode" inManagedObjectContext:context];
[execQuery setEntity:descOggetto];
NSError *error = nil;
_arr = [context executeFetchRequest:execQuery error:&error];
for (NSManagedObject *ogg in _arr){
[context deleteObject:ogg];
[_favoriteCollectionView reloadData];
}
NSError *saveError = nil;
[context save:&saveError];
// NSLog(#"Delete");
}
}
How do I delete a single object instead of all?
You haven't shown enough code for me to give you a specific answer. But the general outline is like this:
First you need to get the index path of the cell associated with the managed object you want to delete. How you do that depends on your use case:
NSIndexPath *indexPath = ...;
From there, get the managed object from your data model. If your data model is a mutable array (typical when you only have one section in your collection view):
NSManagedObject *obj = [self.myDataModel objectAtIndex:indexPath.item];
Then you delete the object and remove it from the array:
[obj.managedObjectContext deleteObject:obj];
NSError *saveError = nil
[obj.managedObjectContext save:saveError];
...// error handling
[self.myDataModel removeObject:obj];
Finally, you inform the collection view that you've deleted an item so it can update the display:
[self.collectionView deleteItemsAtIndexPaths:#[indexPath]];
Or if you don't want animation:
[self.collectionView reloadData];
The answer is a little bit different if you're using an NSFetchedResultsController. Some of the above steps would be taken care of in your NSFetchedResultsControllerDelegate implementation as outlined in the documentation. The remaining steps would look something like this:
NSIndexPath *indexPath = ...;
NSManagedObject *obj = [self.fetchedResultsController objectAtIndexPath:indexPath];
[obj.managedObjectContext deleteObject:obj];
NSError *saveError = nil
[obj.managedObjectContext save:saveError];
...// error handling

how to pass objects between view controllers

I have a table view that lists athletes. when an athlete is selected, I wish to have the detail view controller (the controller that is pushed onto the stack) to know all the attributes about the athlete. his/her name, birthday, phone number, etc. But im unsure on how to pass this information.
allathletes.h
-(void)viewWillAppear:(BOOL)animated{
AppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
_managedObjectContext = [appDelegate managedObjectContext];
NSFetchRequest *request = [[NSFetchRequest alloc] init];
NSEntityDescription *athlete = [NSEntityDescription entityForName:#"Athlete" inManagedObjectContext:_managedObjectContext];
[request setEntity:athlete];
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"last" ascending:YES];
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 setAthleteArray:mutableFetchResults];
[self.tableView reloadData];
}
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
NSString *segueIdentifier = [segue identifier];
if ([segueIdentifier isEqualToString:#"setAthlete"])
{
UINavigationController *navController = (UINavigationController *)[segue destinationViewController];
AllAthletes *athleteList = (AllAthletes *)[[navController viewControllers] lastObject];
//the line below gets an error :(
AthleteDetail.managedObjectContext = self.managedObjectContext;
}
}
Before pushing a detail view controller, set a property on it with the data to be displayed, like:
myDetailViewController.myModel = selectedModel;
In the detail view, you can set up the view using this data in viewWillAppear.
I think you're going to want to use delegates. Here is a great tutorial on how to do that: Link

Resources