I'm trying to change the fetchRequest's predicate on my NSFetchedResultsController, but when i try to reload the data from the aqgridview, none cell is displayed.
My code:
[NSFetchedResultsController deleteCacheWithName: nil];
NSPredicate *predicate = [NSPredicate predicateWithFormat: #"colection = %#", newcolection ];
[fetchedResultsController.fetchRequest setPredicate:predicate];
NSError *error = nil;
if (![[self fetchedResultsController] performFetch:&error]) {
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
abort();
}
[comicGridView reloadData];
SOLVED:
OK, solved. I had to change the "setContentSize: (CGSize) newSize" method in AQGridView.m:
From:
if (newSize.height < footerHeight + minimumHeight)
To:
if (newSize.height < minimumHeight)
As minimumHeight already contains footerHeight, before, footerHeight is added in twice.
I've solved: answer in the question.
Related
On [context save:&error] method, i get this error, but not alwasy. It crashes randomly.
There is no error description.
XCode 9.2, ios 10.3.3
What should i do?
Code:
-(void)changeReadStatusOfConversationWithConvID:(int)convID isRead:(BOOL)isRead{
NSManagedObjectContext *context = [[AppDelegate sharedAppDelegate] managedObjectContext];
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"conversation_id == %d", convID];
NSArray *conversations = [self getObjectsForMessageWithEntity:ENTITY_CONVERSATION withPredicate:predicate];
ConversationManagedObject *conversationManagedObj = [conversations firstObject];
if(conversationManagedObj){
conversationManagedObj.unread = !isRead;
__block NSError *error = nil;
if (![[NSThread currentThread] isMainThread]) {
dispatch_async(dispatch_get_main_queue(), ^{
if(![context save:&error]){
NSLog(#"Cant Update Conversation! %# %#", error, [error localizedDescription]);
}else{
NSLog(#"Conversation Updated!!!");
}
});
}else{
if(![context save:&error]){
NSLog(#"Cant Update Conversation! %# %#", error, [error localizedDescription]);
}else{
NSLog(#"Conversation Updated!!!");
}
}
}
}
enter image description here
First question here and I've tried a bunch of stuff and can't figure it out.
Core Data with 2 entities with to-many relationship both ways
A<<---->>B
A entity has name as an attribute, and a relationship Bs
First Controller lists all A entities and i have a second controller to add A entities and I want to have it save a default B in its relationship.
In the prepare for segue I have this code:
if ([[segue identifier] isEqualToString:#"addAEntitySegue"]) {
AddAEntityViewController *addAEntityViewController = [segue destinationViewController];
addAEntityViewController.delegate = self;
addAEntityViewController.managedObjectContext = self.managedObjectContext;
NSManagedObjectContext *addingContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
self.addingManagedObjectContext = addingContext;
[addingManagedObjectContext setPersistentStoreCoordinator:[[fetchedResultsController managedObjectContext] persistentStoreCoordinator]];
addAEntityViewController.A = [NSEntityDescription insertNewObjectForEntityForName:#"A" inManagedObjectContext:addingContext];
UIBarButtonItem *saveButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemSave
target:addAEntityViewController
action:#selector(save:)];
addAEntityViewController.navigationItem.rightBarButtonItem = saveButton;
}
In addAEntityViewController i have this to save
-(IBAction)save:(id)sender
{
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"B" inManagedObjectContext:self.managedObjectContext];
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"name == %#",[defaults objectForKey:#"BDefault"]];
[fetchRequest setEntity:entity];
[fetchRequest setPredicate:predicate];
//Set the batch size to a suitable number
[fetchRequest setFetchBatchSize:20];
NSError *error;
self.A.name = textFieldVal;
[self.A addBObject:[[self.managedObjectContext executeFetchRequest:fetchRequest error:&error] objectAtIndex:0]];
NSLog(#"A = %#", self.A.Bs);
[self.delegate addAEntityViewController:self didFinishWithSave:YES];
}
In the addAEntityViewController everything saves correctly even the NSLog(#"A = %#", self.A.Bs); statement shows the B. But when the delegate saves in the First Controller (AEntityViewController) it only saves the A.name but not the relationship A.Bs, I can't figure out what's wrong.
Here's the delegate method:
-(void) addAEntityViewController:self didFinishWithSave:YES{
if (save) {
NSLog(#"saveworkouts");
NSError *error;
if (![addingManagedObjectContext save:&error]) {
// Update to handle the error appropriately.
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
exit(-1); // Fail
}
}
// release the adding managed object context
self.addingManagedObjectContext = nil;
}
Like I said it saves the A entity but not the relationship to B even though the relationship to B saved correctly in the addAEntityViewController (the second View). An NSLOg of A.Bs is null.
First I believe that this line:
addAEntityViewController = self.managedObjectContext;
should be:
addAEntityViewController.managedObjectContext = self.managedObjectContext;
but that would also be wrong.
it should be getting the addingContext you created afterwards:
addAEntityViewController.managedObjectContext = addingContext;
I'm a bit surprised that your app didn't crash, as you are mixing managed objects from 2 different contexts.
I'm trying to pop an alert that says "No records found" if the user does a search and the predicate returns nil.
I tried this, but the alert never gets called. I just get an empty tableview.
- (void)searchBarSearchButtonClicked:(UISearchBar *)searchBar {
if (self.sBar.text != nil){
NSPredicate *template = [NSPredicate predicateWithFormat:#"name contains[cd] $SEARCH OR optionOne contains[cd] $SEARCH OR optionTwo contains[cd] $SEARCH"];
NSDictionary *replace = [NSDictionary dictionaryWithObject:self.sBar.text forKey:#"SEARCH"];
NSPredicate *predicate = [template predicateWithSubstitutionVariables:replace];
[fetchedResultsController.fetchRequest setPredicate:predicate];
}
[[fetchedResultsController fetchedObjects] count];
if (fetchedResultsController.fetchedObjects != nil) {
//do nothing
} else {
//display alert
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:nil message:#"No records match."
delegate:self cancelButtonTitle:#"OK" otherButtonTitles:nil];
[alert show];
[alert release];
}
NSError *error = nil;
if (![[self fetchedResultsController] performFetch:&error]) {
// Handle error
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
abort(); // Fail
}
[self.myTable reloadData];
[sBar resignFirstResponder];
}
A predicate does not have a -count. A predicate is an expression that evaluates to true or false. That's it.
You can ask the NSFetchedResultsController for its -fetchedObjects (which returns an array), and then ask that array for its -count, but you can only do this after you invoke -performFetch:.
Ha ha! Got it...
- (void)searchBarSearchButtonClicked:(UISearchBar *)searchBar {
if (self.sBar.text != nil) {
NSPredicate *template = [NSPredicate predicateWithFormat:#"name contains[cd] $SEARCH OR optionOne contains[cd] $SEARCH OR optionTwo contains[cd] $SEARCH"];
NSDictionary *replace = [NSDictionary dictionaryWithObject:self.sBar.text forKey:#"SEARCH"];
NSPredicate *predicate = [template predicateWithSubstitutionVariables:replace];
[fetchedResultsController.fetchRequest setPredicate:predicate];
}
NSError *error = nil;
if (![[self fetchedResultsController] performFetch:&error]) {
// Handle error
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
exit(-1); // Fail
}
if ([[fetchedResultsController fetchedObjects] count] != 0) {
[self.myTable reloadData];
[sBar resignFirstResponder];
}
else {
//display alert
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:nil message:#"No records match."
delegate:self cancelButtonTitle:#"OK" otherButtonTitles:nil];
[alert show];
[alert release];
}
}
I have two entities, Job and Client. The relationship from job to client is called clientOfJob which is a many-to-one relationship:
Job<<-->Client
I am trying to understand how I would sort my fetch results into sections for the table view, with the sections based on client first names.
This is my first attempt to use sectionNameForKeyPath, but I am using sample code from CoreDataBooks, and so far, substituting some of that code has eliminated some serious problems I had earlier today.
Here is the code I tried. I didn't think it would work, but I'm not sure what I need to use for the client sort descriptor key and for the sectionNameKeyPath.
By the way, the code works well with only the jobSortDescriptor (without the clientSortDescriptor) and with sectionNameKeyPath set to nil. Then it just sorts by job description. I can get at the related client entity information, putting client name information into the detailedTextLabel of each cell while I have the job description in the textLabel of the cell.
- (NSFetchedResultsController *) fetchedResultsController {
if (fetchedResultsController != nil) {
return fetchedResultsController;
}
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription * entity = [NSEntityDescription entityForName:#"Job" inManagedObjectContext:dataInterface.managedObjectContext];
[fetchRequest setEntity:entity];
[fetchRequest setFetchBatchSize:10];
NSSortDescriptor *clientSortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"clientOfJob.firstName" ascending:YES];
NSSortDescriptor *jobSortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"jobDescription" ascending:YES];
NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:clientSortDescriptor, jobSortDescriptor, nil];
[fetchRequest setSortDescriptors:sortDescriptors];
NSFetchedResultsController *aFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:dataInterface.managedObjectContext sectionNameKeyPath:#"clientOfJob.firstName" cacheName:#"Jobs"];
aFetchedResultsController.delegate = self;
self.fetchedResultsController = aFetchedResultsController;
[aFetchedResultsController release];
[fetchRequest release];
[jobSortDescriptor release];
[clientSortDescriptor release];
[sortDescriptors release];
NSError *error = nil;
if (![self.fetchedResultsController performFetch:&error]) {
NSLog(#"Unresolved Error %#, %#", error, [error userInfo]);
abort();
}
return fetchedResultsController;
}
I fetch data from a Core Data-base and present them in a UITableView. I use a NSFetchedResultController to fetch the data. I want the user to be able to search in the database, and to do that I use a NSPredicate.
The data is presented in the UITableView and everything works well until I set the NSPredicate to the NSFetchedResultController.
I use this in the ViewDidLoad method:
self.fetchedResultsController = nil;
fetchedResultsController_ = nil;
NSError *error = nil;
if (![[self fetchedResultsController] performFetch:&error]) {
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
exit(-1);
}
and when the user has entered a text from the UITextField, that text will go to the new NSPredicate.
This is done when the search starts:
NSPredicate *pred = nil;
pred = [NSPredicate predicateWithFormat:#"(Designation BEGINSWITH '22')"];
[fetchedResultsController_.fetchRequest setPredicate:pred];
NSError *error = nil;
if (![[self fetchedResultsController] performFetch:&error]) {
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
exit(-1);
}
[tView reloadData];
Right now I use #"(Designation BEGINSWITH '22')" for testing only.
This is my NSFetchedResultsController:
- (NSFetchedResultsController *)fetchedResultsController {
if (fetchedResultsController_ != nil) {
return fetchedResultsController_;
}
/*
Set up the fetched results controller.
*/
// Create the fetch request for the entity.
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
// Edit the entity name as appropriate.
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Product" inManagedObjectContext:importContext];//self.managedObjectContext
[fetchRequest setEntity:entity];
// Set the batch size to a suitable number.
[fetchRequest setFetchBatchSize:20];
// Edit the sort key as appropriate.
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"Designation" ascending:NO];
NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor, nil];
[fetchRequest setSortDescriptors:sortDescriptors];
// Edit the section name key path and cache name if appropriate.
// nil for section name key path means "no sections".
NSFetchedResultsController *aFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:importContext sectionNameKeyPath:nil cacheName:#"Root"]; //self.managedObjectContext
aFetchedResultsController.delegate = self;
self.fetchedResultsController = aFetchedResultsController;
[aFetchedResultsController release];
[fetchRequest release];
[sortDescriptor release];
[sortDescriptors release];
return fetchedResultsController_;
}
The problem is that the fetched data stays the same, no matter how or if I set a predicate. If I would set a predicate in the viewDidLoad it would work, but then I wouldn't be able to get new results if I'd tried that again. I use an "importContext" for a batch-import of my CoreData.
Any ideas?
Thanks in advance!
UPDATE:
Ok, here is what I found out. I have an importContext where I make a batch-import. And for the fetchController I use self.managedObjectContext. That's why it doesn't work, so I have to make self.managedObjectContext have the same stuff as my importContext somehow...
You're using a cache (#"Root")… Try setting it to nil, this could prevent crashes. You should not cache FetchedResultsControllers meant to be Predicated.
Even better than setting the cache to nil is giving it a unique name. After posting this question
iPhone - Cache name for NSFetchedResultsController
I added a function to generate UUIDs as my cache names.