May be I'm doing something wrong?
So, I have few Entities with relationship
"Shop->amountIncome and -> amountExpense"
And I'm trying to count total income and expense.
I have dynamic tabelView
I start with
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
and some search
Shop *shop = nil;
if (self.searchPredicate == nil) {
shop = [self.fetchedResultsController objectAtIndexPath:indexPath];
}
else {
shop = [self.fetchedResultsController.fetchedObjects filteredArrayUsingPredicate:self.
searchPredicate][indexPath.row];
}
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"Cell" forIndexPath:indexPath];
cell.textLabel.text = shop.shopName;
So I start with request of my entity "Shop" (it has relationship -> amountIncome and
->amountExpense
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Shop"
inManagedObjectContext:[self managedObjectContext]];
[fetchRequest setEntity:entity];
I have several Shops, so I do predicate by shopName
[fetchRequest setPredicate:[NSPredicate predicateWithFormat:#"shopName = %#", shop.shopName]];
fetchRequest.resultType = NSDictionaryResultType;
after all I do stuff for calculating sum:
NSExpressionDescription *expressionDescription = [[NSExpressionDescription alloc] init];
expressionDescription.name = #"amountIncome";
expressionDescription.expression = [NSExpression expressionForKeyPath:#"#sum.incomes.amountIncome"];
expressionDescription.expressionResultType = NSDecimalAttributeType;
NSExpressionDescription *expressionDescriptionExpense = [[NSExpressionDescription alloc] init];
expressionDescriptionExpense.name = #"amountExpense";
expressionDescriptionExpense.expression = [NSExpression expressionForKeyPath:#"#sum.expenses.amountExpense"];
expressionDescriptionExpense.expressionResultType = NSDecimalAttributeType;
fetchRequest.propertiesToFetch = #[expressionDescription, expressionDescriptionExpense];
NSError *error = nil;
NSArray *result = [self.managedObjectContext executeFetchRequest:fetchRequest error:&error];
NSLog(#"%#",result);
if (result == nil)
{
NSLog(#"Error: %#", error);
}
else
{
NSNumber *sumOfAmounts = [[result objectAtIndex:0] objectForKey:#"amountIncome"];
NSNumber *sumOfAmountsExpense = [[result objectAtIndex:0] objectForKey:#"amountExpense"];
NSString* amount = [NSString stringWithFormat:#"inc %#/ exp %#/ difference",
sumOfAmounts, sumOfAmountsExpense];
and results I'd like to show in detailTextLabel
cell.detailTextLabel.text = amount;
}
return cell;
The thing is, that amountIncome counting correct, but amountExpense counting wrong (like double counting)
What I'm missing, what my mistake?
P.S. Sorry my English ;(
Have you tried KVC?
NSNumber *sumIncome = [allIncomes valueForKeyPath:#"#sum.amountIncome"];
NSNumber *sumExpense = [allExpenses valueForKeyPath:#"#sum.amountExpense"];
Related
Here's my problem:
I've got 2 Entities :
Session (Date date, String name, NSSet behaviours)
Behaviour (String category, String Time, String name, NSManagedobject session).
They are in a one-to-many relationship.
In SessioneViewController, I fetch the Session and the Behaviours:
// This is for the fetch request
#property (nonatomic, ratain) NSArray *sessionArray;
// Here I create the Session Object
Session *newSession = [NSEntityDescription insertNewObjectForEntityForName:#"Session" inManagedObjectContext:self.managedObjectContext];
newSession.name = self.lblName.text;
newSession.date = [NSDate date];
self.managedObjectContext save:nil];
// I add the Session into the Array
self.sessionsArray = [self.sessionsArray arrayByAddingObject:newSession];
// Here I create the Behaviour Object:
Comportamento *newBehaviour = [NSEntityDescription insertNewObjectForEntityForName:#"Behaviour" inManagedObjectContext:self.managedObjectContext];
newBehaviour.name = cell.textLabel.text;
newBehaviour.category = #"Relationship";
newBehaviour.time = _lblTimer.text;
// Here I say which Session is part of the Behaviour
// --- EDIT ---
// Error Code: newBehaviour.session = [self.sessionsArray objectAtIndex:indexPath.row];
newBehaviour.session = [self.sessionsArray lastObject];
Then I have two view controller classes in which I want to display the Sessions and then when a Session is selected I want the related Behaviours.
// In "ArchiveSessionVC.h":
#property (nonatomic, strong) NSFetchedResultsController *frs;
// In "ArchiveSessionVC.m":
- (void) viwDidLoad
{
if(![[self frs] performFetch:&e]) {
NSLog(#"Error %#", e);
abort();
}
-(NSFetchedResultsController *)frs {
if (_frs != nil) {
return _frs;
}
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Session" inManagedObjectContext:self.managedObjectContext];
[fetchRequest setEntity:entity];
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"date"
ascending:NO];
NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor, nil];
[fetchRequest setSortDescriptors:sortDescriptors];
_frs = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:self.managedObjectContext sectionNameKeyPath:nil cacheName:nil];
return _fetchedResultControllerSessions;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"SessioneCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
Sessione *sessione = [self.fetchedResultControllerSessions objectAtIndexPath:indexPath];
cell.textLabel.text = sessione.nome;
return cell;
}
Here is where I push the Second view controller for display the Behaviuors:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
// Push del ViewController dei comportamenti:
ArchiveBehaviuorsVC *aBehavioursVC = [[ArchiveBehaviuorsVC alloc] initWithNibName:#"ArchiveBehaviuorsVC" bundle:nil];
aBehavioursVC.sessioneSelezionata = [self.fetchedResultControllerSessions objectAtIndexPath:indexPath];
[self.navigationController pushViewController:aBehavioursVC animated:YES];
}
My ArchiveBehaviuorsVC is like this:
//"ArchiveBehaviuorsVC.h"
#property (nonatomic, strong) Session *selectedSession;
-(NSFetchedResultsController *)fetchedResultControllerBehaviours
{
if (_fetchedResultControllerBehaviours != nil) {
return _fetchedResultControllerBehaviours;
}
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Behaviour" inManagedObjectContext:self.managedObjectContext];
//NSPredicate *predicate = [NSPredicate predicateWithFormat:#"session == %#",self.sessioneSelezionata];
[fetchRequest setEntity:entity];
[fetchRequest setPredicate:predicate];
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"nome"
ascending:NO];
NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor, nil];
[fetchRequest setSortDescriptors:sortDescriptors];
_fetchedResultControllerBehaviours = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:self.managedObjectContext sectionNameKeyPath:nil cacheName:nil];
return _fetchedResultControllerBehaviours;
}
This is part of the code but it doesn't work. How do I tell the fetchedResultzController to display only the Behaviours associate with the Session?
-- EDIT ---
I found the problem, it wasn't a NSPredicate error, the problem was in this line of code:
// Error Code: newBehaviour.session = [self.sessionsArray objectAtIndex:indexPath.row];
// Right Code:
newBehaviour.session = [self.sessionsArray lastObject];
The predicate
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"session == %#",self.sessioneSelezionata];
looks ok to me.
Are you sure you are obtaining the wrong behavior? Did you try to enable SQL debugging?
-com.apple.CoreData.SQLDebug X
where X can be 1,2 or 3. The higher the value the more SQL output.
In addition, when you do a save ALWAYS pass in an error reference.
NSError* error = nil;
[context save:&error];
The above snippet returns a bool value so check it. If NO is returned print the error.
I have a project where I'm consuming data from several web services and then storing them in separate entities in Core Data. To be precise there are 4 different entities. 3 of them are storing just fine. The 4th stores in Core Data and I can retrieve it later in other views but if I close the app and open it back up the InventoryImage Entity seems to be empty.
- (void)viewDidLoad {
[super viewDidLoad];
id delegate = [[UIApplication sharedApplication]delegate];
self.managedObjectContext = [delegate managedObjectContext];
_isConnected = TRUE;
[self checkOnlineConnection];
DealerModel *dealer = [[DealerModel alloc]init];
[dealer getDealerNumber];
_dealerNumber = dealer.dealerNumber;
//_dealerNumber = #"000310";
if (_isConnected == TRUE) {
[self downloadInventoryData:_dealerNumber];
[self downloadImages:_dealerNumber];
}
else{
[self loadInventory];
[self loadImages];
}
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
/* Table Data */
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [_modelsArray count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
InventoryCell *cell = (InventoryCell *)[tableView dequeueReusableCellWithIdentifier:[_inventoryCell reuseIdentifier]];
if (cell == nil) {
[[NSBundle mainBundle] loadNibNamed:#"InventoryCell" owner:self options:nil];
cell = _inventoryCell;
_inventoryCell = nil;
}
InventoryHome *currentHome = [_modelsArray objectAtIndex:indexPath.row];
NSNumber *imageCount = [self loadImagesBySerialNumber:currentHome.serialNumber];
cell.lblModelDescription.text = currentHome.homeDesc;
cell.lblSerialNumber.text = currentHome.serialNumber;
cell.lblImageCount.text = [NSString stringWithFormat:#"Images: %#", imageCount];
return cell;
}
/* End Table Data */
/* Start Downloads */
#pragma mark - Inventory and Image Data
- (void)downloadInventoryData:(NSString *)dealerNumber
{
[self loadInventory];
if (_isConnected == 1 && [_modelsArray count] > 0) {
[self clearModelEntity:#"InventoryHome"];
}
NSString *urlString = [NSString stringWithFormat:#"%#%#", webServiceInventoryListURL, dealerNumber];
NSURL *invURL = [NSURL URLWithString:urlString];
NSData *data = [NSData dataWithContentsOfURL:invURL];
NSLog(#"Inventory Web Service URL: %#", invURL);
// Sticks all of the jSON data inside of a dictionary
_jSON = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:nil];
// Creates a dictionary that goes inside the first data object eg. {data:[
_dataDictionary = [_jSON objectForKey:#"data"];
// Check for other dictionaries inside of the dataDictionary
for (NSDictionary *modelDictionary in _dataDictionary) {
InventoryHome *home = [NSEntityDescription insertNewObjectForEntityForName:#"InventoryHome" inManagedObjectContext:[self managedObjectContext]];
NSString *trimmedSerialNumber = [NSString stringWithFormat:#"%#",[NSLocalizedString([modelDictionary objectForKey:#"serialnumber"], nil) stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]]];
home.homeDesc = NSLocalizedString([modelDictionary objectForKey:#"description"], nil);
home.serialNumber = trimmedSerialNumber;
home.brandDesc = NSLocalizedString([modelDictionary objectForKey:#"branddescription"], nil);
home.beds = [NSNumber numberWithInt:[NSLocalizedString([modelDictionary objectForKey:#"numberofbedrooms"], nil) intValue]];
home.baths = [NSNumber numberWithInt:[NSLocalizedString([modelDictionary objectForKey:#"numberofbathrooms"], nil) intValue]];
home.sqFt = [NSNumber numberWithInt:[NSLocalizedString([modelDictionary objectForKey:#"squarefeet"], nil) intValue]];
home.length = [NSNumber numberWithInt:[NSLocalizedString([modelDictionary objectForKey:#"length"], nil) intValue]];
home.width = [NSNumber numberWithInt:[NSLocalizedString([modelDictionary objectForKey:#"width"], nil) intValue]];
}
[self loadInventory];
}
- (void)downloadImages:(NSString *)dealerNumber
{
[self loadImages];
if (_isConnected == 1 && [_imagesArray count] > 0) {
[self clearModelEntity:#"InventoryImage"];
}
NSString *stringImageURL = [NSString stringWithFormat:#"%#%#",inventoryImageURL, dealerNumber];
NSURL *url = [NSURL URLWithString:stringImageURL];
NSData *imageData = [NSData dataWithContentsOfURL:url];
_jSON = [NSJSONSerialization JSONObjectWithData:imageData options:kNilOptions error:nil];
_dataDictionary = [_jSON objectForKey:#"data"];
for (NSDictionary *imageDictionary in _dataDictionary) {
InventoryImage *image = [NSEntityDescription insertNewObjectForEntityForName:#"InventoryImage" inManagedObjectContext:[self managedObjectContext]];
NSString *trimmedSerialNumber = [NSString stringWithFormat:#"%#",[NSLocalizedString([imageDictionary objectForKey:#"serialnumber"], nil) stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]]];
image.assetID = NSLocalizedString([imageDictionary objectForKey:#"aid"], nil);
image.sourceURL = NSLocalizedString([imageDictionary objectForKey:#"imagereference"], nil);
image.serialNumber = trimmedSerialNumber;
image.group = NSLocalizedString([imageDictionary objectForKey:#"imagegroup"], nil);
image.imageTagId = [NSString stringWithFormat:#"%#", [imageDictionary objectForKey:#"searchtagid"]];
image.imagesId = [NSString stringWithFormat:#"%#", [imageDictionary objectForKey:#"imagesid"]];
image.imageCaption = NSLocalizedString([imageDictionary objectForKey:#"imagecaption"], nil);
image.imageSource = NSLocalizedString([imageDictionary objectForKey:#"imagesource"], nil);
image.inventoryPackageID = NSLocalizedString([imageDictionary objectForKey:#"inventorypackageid"], nil);
}
}
/* End Downloads */
/* Load Inventory and Image From Core Data */
- (void)loadInventory
{
_fetchRequest = [[NSFetchRequest alloc]init];
_entity = [NSEntityDescription entityForName:#"InventoryHome" inManagedObjectContext:[self managedObjectContext]];
_sort = [NSSortDescriptor sortDescriptorWithKey:#"homeDesc" ascending:YES];
_sortDescriptors = [[NSArray alloc]initWithObjects:_sort, nil];
[_fetchRequest setSortDescriptors:_sortDescriptors];
[_fetchRequest setEntity:_entity];
NSError *error = nil;
_modelsArray = [[self managedObjectContext] executeFetchRequest:_fetchRequest error:&error];
if (![[self managedObjectContext]save:&error]) {
NSLog(#"An error has occurred: %#", error);
}
[self.inventoryListTable reloadData];
}
- (NSNumber *)loadImagesBySerialNumber: (NSString *)serialNumber
{
_imagesFetchRequest = [[NSFetchRequest alloc]init];
_imagesEntity = [NSEntityDescription entityForName:#"InventoryImage" inManagedObjectContext:[self managedObjectContext]];
_imagesPredicate = [NSPredicate predicateWithFormat:#"serialNumber = %# && group <> 'm-FLP' && imageSource <> 'MDL'", serialNumber];
[_imagesFetchRequest setEntity:_imagesEntity];
[_imagesFetchRequest setPredicate:_imagesPredicate];
NSError *error = nil;
_imagesArray = [[self managedObjectContext] executeFetchRequest:_imagesFetchRequest error:&error];
NSNumber *imageCount = [NSNumber numberWithInteger:[_imagesArray count]];
return imageCount;
}
- (void)loadImages
{
_imagesFetchRequest = [[NSFetchRequest alloc]init];
_imagesEntity = [NSEntityDescription entityForName:#"InventoryImage" inManagedObjectContext:[self managedObjectContext]];
[_imagesFetchRequest setEntity:_imagesEntity];
NSError *error = nil;
_imagesArray = [[self managedObjectContext] executeFetchRequest:_imagesFetchRequest error:&error];
}
/* End Load Inventory and Image From Core Data */
- (void)clearModelEntity:(NSString *)entity
{
_fetchRequest = [[NSFetchRequest alloc]init];
_entity = [NSEntityDescription entityForName:entity inManagedObjectContext:[self managedObjectContext]];
[_fetchRequest setEntity:_entity];
NSError *error = nil;
_modelsArray = [[self managedObjectContext] executeFetchRequest:_fetchRequest error:&error];
for (NSManagedObject *object in _modelsArray) {
[[self managedObjectContext] deleteObject:object];
}
NSError *saveError = nil;
if (![[self managedObjectContext] save:&saveError]) {
NSLog(#"An error has occurred: %#", saveError);
}
}
- (void)clearImageEntity:(NSString *)entity
{
_fetchRequest = [[NSFetchRequest alloc]init];
_entity = [NSEntityDescription entityForName:entity inManagedObjectContext:[self managedObjectContext]];
[_fetchRequest setEntity:_entity];
NSError *error = nil;
_imagesArray = [[self managedObjectContext] executeFetchRequest:_fetchRequest error:&error];
for (NSManagedObject *object in _imagesArray) {
[[self managedObjectContext] deleteObject:object];
}
NSError *saveError = nil;
if (![[self managedObjectContext] save:&saveError]) {
NSLog(#"An error has occurred: %#", saveError);
}
}
Don't forget to call [save:conetext]. if you close without saving you will lost your data.
I've got a property NSMutableArray in my view controller
ContactsViewController.h:
#interface ContactsViewController : UIViewController <UITableViewDelegate, UITableViewDataSource>
#property (nonatomic,strong) NSMutableArray *contacts;
...
#end
In this view controller I fill my array on "viewDidLoad"
ContactsViewController.m:
#implementation ContactsViewController
#synthesize contacts;
...
...
- (void)viewDidLoad
{
[super viewDidLoad];
DBhandler *handler = [[DBhandler alloc] init];
if (contacts)
[contacts removeAllObjects];
else
contacts = [[NSMutableArray alloc] init];
// Get all my contacts that are in my core data file
// This function returns a NSMutableArray
contacts=[handler getContacts];
//loop through contacts of addressbook when user wants that
if ([allContactSwitch isOn])
{
//open link to addressbook
ABAddressBookRef addressBook = ABAddressBookCreate();
CFArrayRef allPeople = ABAddressBookCopyArrayOfAllPeople( addressBook );
CFIndex nPeople = ABAddressBookGetPersonCount( addressBook );
for( CFIndex personIndex = 0; personIndex < nPeople; personIndex++ ) {
ABRecordRef refVal = CFArrayGetValueAtIndex( allPeople, personIndex );
Boolean newContact = true;
// check if contact is already in Core data File
for( CFIndex i = 0; i < [contacts count]; i++ ) {
contact *checkcontact=[contacts objectAtIndex:i];
if (personIndex==checkcontact.personRef)
newContact = FALSE;
}
if (newContact)
{
contact *dummycontact = [[contact alloc]init];
dummycontact.personRef = personIndex;
dummycontact.contactName = (__bridge NSString *)(ABRecordCopyCompositeName( refVal ));
// Add contact to array
[contacts addObject:dummycontact];
}
}
}
// Just to check, the entire array looks fine!
for( CFIndex i = 0; i < [contacts count]; i++ ) {
contact *dummycontact=[contacts objectAtIndex:i];
NSLog(#"Name after build: %#", dummycontact.contactName);
}
}
But later when the different cell for the table view are filled, the part of the NSMutableArray that came from [handle getContacts] are empty:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
//NSLog(#"cell number %i",indexPath.row);
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:CellIdentifier];
}
// Set up the cell...
contact *dummycontact=[contacts objectAtIndex:indexPath.row];
// Only part of the objects in the array contacts contain data!
NSLog(#"Name cell: %# %i", dummycontact.contactName, indexPath.row);
cell.textLabel.text = dummycontact.contactName;
return cell;
}
This probably has to do with the fact that the memory of the objects created in [handle getContacts] is cleared in the meantime. But I don't know how to solve this. I've tried clone or copy the output of [handle get contacts], but I wasn't successful.
To be complete the function "getContacts":
-(NSMutableArray*)getContacts{
NSMutableArray *contacts = [[NSMutableArray alloc] init];
NSManagedObjectContext *context = [self managedObjectContext];
DBcontact *contact = [NSEntityDescription
insertNewObjectForEntityForName:#"WhappContacts"
inManagedObjectContext:context];
// Test listing all FailedBankInfos from the store
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"WhappContacts"
inManagedObjectContext:context];
[fetchRequest setEntity:entity];
NSError *error;
NSArray *fetchedObjects = [context executeFetchRequest:fetchRequest error:&error];
for (contact in fetchedObjects) {
[contacts addObject:contact];
// Data seems fine here.
NSLog(#"Name in: %#", contact.contactName);
}
return contacts;
}
Any help would be very appreciated!
An alternative would be to place the contact information in a dictionary:
- (NSMutableArray*)getContacts {
NSMutableArray *contacts = [[NSMutableArray alloc] init];
NSManagedObjectContext *context = [self managedObjectContext];
DBcontact *contact = [NSEntityDescription insertNewObjectForEntityForName:#"WhappContacts" inManagedObjectContext:context];
// Test listing all FailedBankInfos from the store
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"WhappContacts" inManagedObjectContext:context];
[fetchRequest setEntity:entity];
NSError *error;
NSArray *fetchedObjects = [context executeFetchRequest:fetchRequest error:&error];
for (contact in fetchedObjects) {
NSDictionary *contactDict = [NSDictionary dictionaryWithObjectsAndKeys:
contact.contactName, #"contactName", nil]; //add other necessary contact information
[contacts addObject:contactDict];
// Data seems fine here.
NSLog(#"Name in: %#", contact.contactName);
}
return contacts;
}
And to retrieve the information:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
//NSLog(#"cell number %i",indexPath.row);
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
// Set up the cell...
NSDictionary *dummycontact = [contacts objectAtIndex:indexPath.row];
// Only part of the objects in the array contacts contain data!
NSLog(#"Name cell: %# %i", [dummycontact objectForKey:#"contactName"], indexPath.row);
cell.textLabel.text = [dummycontact objectForKey:#"contactName"];
return cell;
}
I've been trying to get through this for a couple of hours now and trying to figure out what is wrong with this code. I'm using core data to save title and a subtitle in a table cell.
I have some setups in my app delegate(sharedAppDelegate) and in my tableview is were I try to inset data into my cells.
Here is what I have in My appDelegate.m:
+(StaticTableAppDelegate *)sharedAppDelegate
{
return sharedInstance;
}
-(NSArray *)allConsoles
{
NSManagedObjectContext *moc = [[StaticTableAppDelegate sharedAppDelegate] managedObjectContext];
NSFetchRequest *fetch = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Homework" inManagedObjectContext:moc];
[fetch setEntity:entity];
//sort
NSSortDescriptor *sd = [[NSSortDescriptor alloc] initWithKey:#"title" ascending:YES];
NSArray *sortdescriptors = [NSArray arrayWithObject:sd];
[fetch setSortDescriptors:sortdescriptors];
NSError *error;
NSArray *result = [moc executeFetchRequest:fetch error:&error];
if(!result){
NSLog(#"%#", [error localizedDescription]);
return nil;
}
return result;
}
And in the view I have this(I imported app delegate):
- (void)viewDidLoad
{
[super viewDidLoad];
NSManagedObjectContext *cxt = [[StaticTableAppDelegate sharedAppDelegate] managedObjectContext];
NSError *error;
NSFetchRequest *request = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Homework" inManagedObjectContext:cxt];
[request setEntity:entity];
NSArray *arry = [cxt executeFetchRequest:request error:&error];
for( UserData *user in arry){
NSLog(#"title %#", user.title);
NSLog(#"details %#", user.details);
}
StaticTableAppDelegate *ad = [StaticTableAppDelegate sharedAppDelegate];
NSArray *list = [ad allConsoles];
if ([list count]==0) {
tabledata = [[NSMutableArray alloc] init];
tablesubtitles = [[NSMutableArray alloc]init];
[tabledata addObject:#"hello2"];
[tabledata addObject:#"hello2"];
[tabledata addObject:#"hello2"];
[tabledata addObject:#"hello2"];
[tablesubtitles addObject:#"details"];
[tablesubtitles addObject:#"details"];
[tablesubtitles addObject:#"details"];
[tablesubtitles addObject:#"details"];
NSManagedObjectContext *moc = [ad managedObjectContext];
for (int i=0; i<[tabledata count]; i++) {
NSManagedObject *newTabledata = [NSEntityDescription insertNewObjectForEntityForName:#"Homework" inManagedObjectContext:moc];
[newTabledata setValue:[NSString stringWithFormat:[tabledata objectAtIndex:i]] forKey:#"title"];
NSManagedObject *newTablesub = [NSEntityDescription insertNewObjectForEntityForName:#"Homework" inManagedObjectContext:moc];
[newTablesub setValue:[NSString stringWithFormat:[tablesubtitles objectAtIndex:i]] forKey:#"details"];
}
list = [ad allConsoles];
}
tabledata = [tabledata mutableCopy];
}
And tableview method:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath: (NSIndexPath *)indexPath;
{
UITableViewCell *cell = nil;
cell = [tableView dequeueReusableCellWithIdentifier:#"homeworkcell"];
if(cell == nil)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:#"homeworkcell"];
}
cell.textLabel.text=[[tabledata objectAtIndex:indexPath.row] valueForKey:#"title"];
cell.detailTextLabel.text = [[tablesubtitles objectAtIndex:indexPath.row] valueForKey:#"details"];
cell.textLabel.font = [UIFont systemFontOfSize:14.0];
cell.textLabel.backgroundColor = [ UIColor clearColor];
cell.detailTextLabel.backgroundColor = [UIColor clearColor];
//-----------------------------------------START----------------------------Set image of cell----
cellImage = [UIImage imageNamed:#"checkboxblank.png"];
cell.imageView.image = cellImage;
//--------------------------------------------END---------------------------end set image of cell--
return cell;
}
I appreciate the help.
This is how to store into coreData....If u can change it for your code..
MortgageAppAppDelegate *MortDataObj=(MortgageAppAppDelegate *)[[UIApplication sharedApplication]delegate];
NSManagedObjectContext *context = [MortDataObj managedObjectContext];
loanDetails=[NSEntityDescription
insertNewObjectForEntityForName:#"LoanDetails"
inManagedObjectContext:context];
loanDetails.loanName = name;
loanDetails.loanDescription = desc;
NSError *error;
if (![context save:&error]) {
NSLog(#"Whoops, couldn't save: %#", [error localizedDescription]);
}
I have three Classes for which I am extending NSManagedObject (I know this isn't required but I wanted the property notation). Theses Classes are QuestionSet, Question and Answer. My data model is setup so that there's a many to many between them like so: QuestionSet <<->> Question <<->> Answer. I load up everything from a server and it save successfully meaning I look in the .db file and it's all how I expect, if I immediately NSLog the array questionsets they look great and if I go take a quiz it works great.
However if I NSLog that array anywhere but right after where I load them from the server, it crashes my app. The quiz still runs fine so I know the data is in there and in the expected format. Does this have something to do with Core Data clearing out space and then my relationships don't 'lazy loaded' when I'm just trying to log them? Sorry, still wrapping my head around core data.
This bit works, I load from the server and at the bottom I 'loadTrivia' and log what I get. The issue comes if at sometime later during the course of the app execution, an NSLog of the questionsets will fail.
- (void)loadQuestionSetFromNetworkWithID:(NSNumber *)p_id andTitle:(NSString *)p_title
{
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:[NSString stringWithFormat:kTriviaQuestionSetURL, [p_id intValue]]]];
[UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
NSData *response = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:nil];
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
NSString *json_string = [[NSString alloc] initWithData:response encoding:NSUTF8StringEncoding];
NSArray *questions = [[[sbjson objectWithString:json_string error:nil] valueForKeyPath:#"Q"] objectAtIndex:0];
NSError *error;
NSFetchRequest *questionsetRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *questionsetEntity = [NSEntityDescription entityForName:#"QuestionSet" inManagedObjectContext:[self managedObjectContext]];
NSPredicate *questionsetPredicate = [NSPredicate predicateWithFormat:#"id = %d", [p_id intValue]];
[questionsetRequest setEntity:questionsetEntity];
[questionsetRequest setPredicate:questionsetPredicate];
QuestionSet *qs = nil;
NSArray *questionSetObjects = [[self managedObjectContext] executeFetchRequest:questionsetRequest error:&error];
if (questionSetObjects == nil){
// Handle errors
}
if ([questionSetObjects count] > 0)
qs = [questionSetObjects objectAtIndex:0];
else
qs = [NSEntityDescription insertNewObjectForEntityForName:#"QuestionSet" inManagedObjectContext:[self managedObjectContext]];
qs.id = p_id;
qs.title = p_title;
for (int i = 0; i < [questions count]; i++)
{
NSFetchRequest *questionRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *questionEntity = [NSEntityDescription entityForName:#"Question" inManagedObjectContext:[self managedObjectContext]];
NSPredicate *questionPredicate = [NSPredicate predicateWithFormat:#"(id = %d)", [[[questions objectAtIndex:i] objectForKey:#"id"] intValue]];
[questionRequest setEntity:questionEntity];
[questionRequest setPredicate:questionPredicate];
Question *q = nil;
NSArray *questionObjects = [[self managedObjectContext] executeFetchRequest:questionRequest error:&error];
if (questionObjects == nil){
// Handle errors
}
if ([questionObjects count] > 0)
q = [questionObjects objectAtIndex:0];
else
q = [NSEntityDescription insertNewObjectForEntityForName:#"Question" inManagedObjectContext:[self managedObjectContext]];
q.id = [NSNumber numberWithInt:[[[questions objectAtIndex:i] objectForKey:#"id"] intValue]];
q.question = [[questions objectAtIndex:i] objectForKey:#"text"];
q.answer = [NSNumber numberWithInt:[[[questions objectAtIndex:i] objectForKey:#"ca"] intValue]];
for (int j = 0; j < [[[questions objectAtIndex:i] objectForKey:#"A"] count]; j++)
{
NSFetchRequest *answerRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *answerEntity = [NSEntityDescription entityForName:#"Answer" inManagedObjectContext:[self managedObjectContext]];
NSPredicate *answerPredicate = [NSPredicate predicateWithFormat:#"(id = %d)", [[[[[questions objectAtIndex:i] objectForKey:#"A"] objectAtIndex:j] objectForKey:#"id"] intValue]];
[answerRequest setEntity:answerEntity];
[answerRequest setPredicate:answerPredicate];
Answer *a = nil;
NSArray *answerObjects = [[self managedObjectContext] executeFetchRequest:answerRequest error:&error];
if (answerObjects == nil){
// Handle errors
}
if ([answerObjects count] > 0)
a = [answerObjects objectAtIndex:0];
else
a = [NSEntityDescription insertNewObjectForEntityForName:#"Answer" inManagedObjectContext:[self managedObjectContext]];
a.id = [NSNumber numberWithInt:[[[[[questions objectAtIndex:i] objectForKey:#"A"] objectAtIndex:j] objectForKey:#"id"] intValue]];
a.answer = [[[[questions objectAtIndex:i] objectForKey:#"A"] objectAtIndex:j] objectForKey:#"text"];
a.questions = [a.questions setByAddingObject:q];
q.answers = [q.answers setByAddingObject:a];
[answerRequest release];
}
q.questionsets = [q.questionsets setByAddingObject:qs];
qs.questions = [qs.questions setByAddingObject:q];
[questionRequest release];
}
[questionsetRequest release];
[[self managedObjectContext] save:&error];
[json_string release];
[self loadTrivia];
NSLog(#"After Load: %#", self.questionsets);
}
This function fetches all the QuestionSet objects from the db and stores the array in an ivar.
- (BOOL)loadTrivia
{
NSError *error;
NSFetchRequest *request = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"QuestionSet" inManagedObjectContext:[self managedObjectContext]];
[request setEntity:entity];
self.questionsets = [[self managedObjectContext] executeFetchRequest:request error:&error];
return YES;
}
Just for completeness, here are my description methods in my classes
from QuestionSet.h
- (NSString *)description
{
return [NSString stringWithFormat:#"\
\n\tid: %#\
\n\ttitle: %#\
\n\tquestions: %#\n",
self.id,
self.title,
self.questions];
}
from Question.h
- (NSString *)description
{
return [NSString stringWithFormat:#"\
\n\tid: %#\
\n\tanswer: %#\
\n\tquestion: %#\
\n\tanswers: %#\n",
self.id,
self.answer,
self.question,
self.answers];
}
from Answer.h
- (NSString *)description
{
return [NSString stringWithFormat:#"\
\n\tid: %#\
\n\tanswer: %#\n",
self.id,
self.answer];
}
You shouldn't subclass the description method (Link):
Although the description method does not cause a fault to fire, if you implement a custom description method that accesses the object’s persistent properties, this will cause a fault to fire. You are strongly discouraged from overriding description in this way.
I tested your loadTrivia code (with a different entityName) on my app and it worked fine.
Did you have a look at the NSError (you should initialize it with =nil):
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
Also you should release the NSFetchRequest after execution in - (BOOL)loadTrivia.