How to reload TableView data from AppDelegate.m? - objective-c

I've tryed to reload TableView data from AppDelegate.m but with no success.
Here is code (whis is working in HomeViewController):
AppDelegate.m
...
- (void)applicationWillEnterForeground:(UIApplication *)application
{
[self refreshTableData];
}
-(void)refreshTableData{
UINavigationController *navController = [[self.tabBarController viewControllers] objectAtIndex:0];
HomeViewController *home = [[navController viewControllers] objectAtIndex:0];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"MYTable" inManagedObjectContext:home.context];
NSFetchRequest *request = [[NSFetchRequest alloc] init];
[request setFetchBatchSize:20];
[request setEntity:entity];
NSSortDescriptor *sort = [[NSSortDescriptor alloc] initWithKey:#"orderEnt" ascending:YES];
NSArray *newArray = [NSArray arrayWithObject:sort];
[request setSortDescriptors:newArray];
NSError *error;
NSMutableArray *results = [[home.context executeFetchRequest:request error:&error] mutableCopy];
[home setArr:results];
//NSLog(#"%#", home.arr);//here is showed correct data
home.context = self.managedObjectContext;
[home.myTableView reloadData];
}
...
Does anybody know how to reload data from AppDelegate.m?

You could implement
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(reloadTableViewData) name:#"ReloadAppDelegateTable" object:nil];
in your viewDidLoad() method and
- (void)reloadTableViewData{
[self.myTableView reloadData];
}
in the class where you want to reload the Data.
Then you send a Notification like this
[[NSNotificationCenter defaultCenter] postNotificationName:#"ReloadAppDelegateTable" object:nil];
whenever you want to reload the data.
Note after some years of iOS development experience:
While this is a very easy and comfortable solution, it is not 100% reliable. Notifications can be delayed by several seconds under certain circumstances. I would highly recommend to create a fast and reliable delegate connection to your UITableViewController.

Related

core-data is getting old data and not the updated values

I am having this strange issue which has been plaguing me all day, i am updating an object in a background thread which is saving correctly
NSFetchRequest *fetchRequest1 = [[NSFetchRequest alloc] init];
NSEntityDescription *entity1 = [NSEntityDescription entityForName:#"STMilestone"
inManagedObjectContext:tmpContext];
[fetchRequest1 setEntity:entity1];
[fetchRequest1 setReturnsObjectsAsFaults:NO];
NSError *error;
NSString *idNum = [obj valueForKey:#"id"];
// NSUInteger TrackerExists = [tmpContext countForFetchRequest:fetchRequest1 error:&error];
[fetchRequest1 setPredicate:[NSPredicate predicateWithFormat:#"identiferNumber = %#", idNum]];
NSArray *logs = [tmpContext executeFetchRequest:fetchRequest1 error:&error];
NSManagedObject *updateObj = [logs objectAtIndex:0];
[updateObj setValue:[NSNumber numberWithInt:20] forKey:#"progress"];
When i then get this object in the same background thread this gets the correct updated value
However when i go to get this updated value on my main thread it returns the old value, then when i clear the cache and reload the app it pulls the correct data
NSManagedObjectContext *context = [self managedObjectContext];
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"STTracker"
inManagedObjectContext:context];
[fetchRequest setEntity:entity];
[fetchRequest setReturnsObjectsAsFaults:NO];
NSError *error = nil;
NSMutableArray *array = [NSMutableArray arrayWithArray:[context executeFetchRequest:fetchRequest error:&error]];
I think this may be a context issue, my background thread context is being created with this
AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
NSManagedObjectContext *tmpContext = [[NSManagedObjectContext alloc] init];
tmpContext.persistentStoreCoordinator = [appDelegate persistenceCoordinator];
and the main thread is
NSPersistentStoreCoordinator *coordinator = [self persistenceCoordinator];
if(coordinator != nil)
{
_managedObjectContext = [[NSManagedObjectContext alloc] init];
[_managedObjectContext setPersistentStoreCoordinator:coordinator];
NSUndoManager *undoManager = [[NSUndoManager alloc] init];
[undoManager setGroupsByEvent:NO];
[_managedObjectContext setUndoManager:undoManager];
}
[_managedObjectContext setMergePolicy:NSMergeByPropertyStoreTrumpMergePolicy];
However i have updated other objects in my app and they are being pulled through, so any help or insight on why this might be happening would be great
This will not work:
NSManagedObjectContext *tmpContext = [[NSManagedObjectContext alloc] init];
You need to need to init the context with the right concurrency type and assign it the correct parent context (or persistent store coordinator). See the docs
initWithConcurrencyType:
setParentContext:
When child and parent contexts are set up correctly, you an save the child context which does not really write to the persistent store but just "pushes" the changes up to the parent context. The changes are written to the store once you save the parent context again.

Saving CoreData permanently

I have been trying all afternoon to get the CoreData portion of my app working and almost have it working as it should. The problem is that the CoreData does not save appropriate value when the app gets terminated (removed from multitasking menu). The value that remains is the intitial value (in my case 0, defined as NSString) I put into the entity instead of the new value the user entered. So the issue is saving the new value PERMANENTLY after the app is closed and not showing the initial value again when the app is loaded
Entity name: Gameinfo
Attribute: score
I am not sure what I am doing wrong. If anyone could help me, it would be appreciated.
Thanks!
-(IBAction)saveTheory1
{
AppDelegate *appDelegate= [[UIApplication sharedApplication] delegate];
NSManagedObjectContext *context =
[appDelegate managedObjectContext];
NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:#"Gameinfo"];
NSError *error = nil;
NSArray *someArray = [context executeFetchRequest:request error:&error];
[[someArray objectAtIndex:0] setValue:[self showKey] forKey:#"score"]; // showKey gets the text from UITextField
}
-(IBAction)showTheory1;
{
AppDelegate *appDelegate= [[UIApplication sharedApplication] delegate];
NSManagedObjectContext *context =
[appDelegate managedObjectContext];
NSEntityDescription *entityDesc =
[NSEntityDescription entityForName:#"Gameinfo"
inManagedObjectContext:context];
NSFetchRequest *request = [[NSFetchRequest alloc] init];
[request setEntity:entityDesc];
NSManagedObject *matches = nil;
NSError *error;
NSArray *objects = [context executeFetchRequest:request
error:&error];
matches = [objects objectAtIndex:0];
NSLog (#"show us the current value: %#", [matches valueForKey:#"score"]);
}
You are not saving the value at all. You are just assigning it to the Gameinfo object. To actually save it, call save: method on managed object context:
...
[[someArray objectAtIndex:0] setValue:[self showKey] forKey:#"score"];
NSError *saveError = nil;
[[appDelegate managedObjectContext] save:&saveError];
}
It doesnt look like you are calling [context save:error] anywhere. This is what moves your changes into permanent storage.

iOS 5.0 - Pass NSMutableArray from Helper Class to View Controller

I have a helper class designed to get data from Core Data and pass it back to a view controller. Here's the code:
View Controller:
#interface AnnouncementsController : UIViewController
#property (nonatomic, retain) NSMutableArray *announcements;
#end
#implementation AnnouncementsController
#synthesize announcements;
- (void)viewDidLoad
{
AnnouncementCoreDataHelper *announcementHelper = [[AnnouncementCoreDataHelper alloc] init];
self.announcements = [announcementHelper selectAnnouncementsWithPredicate:#"isActive = 1" sortDescriptor:#"lastUpdated" sortAscending:NO];
[super viewDidLoad];
}
#end
And the Core Data Helper implementation:
// Select one or more announcements based on a predicate if passed in and a sort order
- (NSMutableArray*)selectAnnouncementsWithPredicate:(NSString *)predicateString sortDescriptor:(NSString *)sortBy sortAscending:(BOOL)isAscending
{
NSError *error = nil;
// Build the entity and request
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Announcement" inManagedObjectContext:managedObjectContext];
NSFetchRequest *request = [[NSFetchRequest alloc] init];
[request setEntity:entity];
if(predicateString)
{
// Set the search criteria
NSPredicate *predicate = [NSPredicate predicateWithFormat:predicateString];
[request setPredicate:predicate];
}
if(sortBy)
{
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:sortBy ascending:isAscending];
NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor, nil];
[request setSortDescriptors:sortDescriptors];
}
// Perform the search
NSMutableArray *results = [[managedObjectContext executeFetchRequest:request error:&error] mutableCopy];
if(results == Nil)
{
NSLog(#"%#", error);
}
return results;
}
The problem is that the Core Data Helper returns two objects in its NSMutableArray results but the View Controller's NSMutableArray announcements gets nil. What is getting lost in the passing the NSMutableArray back from the helper to the controller? If I change all the variables and results to a NSArray, everything works.
I believe this was a funky issue with Xcode. I clean and reran the build and everything is working. I apologize for wasting your time and thanks for the help! I would like to know more about the memory management issues though.

Objective C - NSManagedObjectContext and NSFetchedResultsController release handling

i need some information about memory management with NSManagedObjectContext objects.
I`m programming on an ipad-App and i work with core data objects.
My UIApplicationDelegate controls the NSManagedObjectContext:
- (NSManagedObjectContext *)managedObjectContext {
if (__managedObjectContext != nil)
{
return __managedObjectContext;
}
NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
if (coordinator != nil)
{
__managedObjectContext = [[NSManagedObjectContext alloc] init];
[__managedObjectContext setPersistentStoreCoordinator:coordinator];
}
return __managedObjectContext;
}
I`m using instances of the ManagedObjectContext to display my Core Data Objects.
like this.
example table view controller:
CRMAppDelegate *appDelegate = (CRMAppDelegate*) [[UIApplication sharedApplication] delegate];
self.managedObjectContext = appDelegate.managedObjectContext;
// Initialize NSFetchedResultsController to retrieve data from the database.
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
[fetchRequest setEntity:[NSEntityDescription entityForName:#"Contact" inManagedObjectContext:self.managedObjectContext]];
// Sort results ascending by last name, first name.
NSSortDescriptor *sortDescriptorFirstLetterLastName = [[NSSortDescriptor alloc] initWithKey:#"firstLetterOfLastName" ascending:YES];
NSSortDescriptor *sortDescriptorLastName = [[NSSortDescriptor alloc] initWithKey:#"name_last" ascending:YES];
NSSortDescriptor *sortDescriptorFirstName = [[NSSortDescriptor alloc] initWithKey:#"name_first" ascending:YES];
NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptorFirstLetterLastName, sortDescriptorLastName, sortDescriptorFirstName, nil];
[fetchRequest setSortDescriptors:sortDescriptors];
[sortDescriptors release];
[sortDescriptorFirstLetterLastName release];
[sortDescriptorFirstName release];
[sortDescriptorLastName release];
/*
if ([self.managedObjectContext countForFetchRequest:fetchRequest error:NULL] == 0) {
[self reloadContactData];
}
*/
// Create NSFetched Results controller instance.
fetchedResultsController = [[NSFetchedResultsController alloc]
initWithFetchRequest:fetchRequest
managedObjectContext:self.managedObjectContext
sectionNameKeyPath:#"firstLetterOfLastName"
cacheName:#"ContactsViewCache"];
[fetchRequest release];
self.fetchedResultsController.delegate = self;
// Load data.
NSError *error;
if (![fetchedResultsController performFetch:&error]) {
// Update to handle the error appropriately.
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
}
Is it ok to instance the NSManagedObjectContext like this? Because, the retainCount of the context is increasing til 10 while i`m testing my APP, even though i'm releasing the the context in "viewDidUnload" and "dealloc".
I`ve tried retain the context in a handler class like this:
- (NSManagedObjectContext *)getManagedObjectContext
{
NSManagedObjectContext *context = [self.managedObjectContext autorelease];
return context;
}
Whats the best way to interact with NSManagedObjectContext - objects and instances?
Thx and sry for my stuoid question :)
The value returned by retainCount is meaningless. Don't bother looking at it.
Use the Leaks instrument or heapshot analysis to determine if your app is leaking.

How to use ManagedObjectContext with threads

This is probably a very straight forward application, but I am new to Objective-C (coming from Java) and the whole memory management and "EXC_BAD_ACCESS" errors are breaking my heart.
I have a normal NavigationController iPhone App, with Core Data. in the AppDelegate the NSManagedObjectContext is created and passed to the RootViewController. A view things are looked up directly from the main thread to populate the table, and that seems to work fine.
The App is somekind of RSS-type reader, so as soon as the App starts I fire a thread to fetch new data and update the view:
-(void)updateData:(id)sender {
UIActivityIndicatorView *activityIndicator =
[[UIActivityIndicatorView alloc] initWithFrame:CGRectMake(0, 0, 20, 20)];
[activityIndicator startAnimating];
UIBarButtonItem *activityItem =
[[UIBarButtonItem alloc] initWithCustomView:activityIndicator];
[activityIndicator release];
self.navigationItem.leftBarButtonItem = activityItem;
[activityItem release];
// Start thread to update the data
[NSThread detachNewThreadSelector:#selector(doUpdateData) toTarget:self withObject:nil];
}
-(void)doUpdateData{
NSLog(#"Update data Thread (in 5 sec.)");
[NSThread sleepForTimeInterval:5];
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
DataManager *data = [[DataManager alloc] initWithContext:managedObjectContext];
[data updateData];
[data release];
data=nil;
[self performSelectorOnMainThread:#selector(finishUpdateData) withObject:nil waitUntilDone:NO];
[pool release];
}
-(void)finishUpdateData{
self.navigationItem.leftBarButtonItem = updateBttn;
DataManager *data = [[DataManager alloc] initWithContext:managedObjectContext];
objects = [data getArticles];
[data release];
data=nil;
NSLog(#"Amount of records after update: %d", [objects count]);
[self.tableView reloadData];
}
The problem is that this doesn't work. In the DataManager, first settings need to be retrieved, and as soon as the NSEntityDescription is created I get the "EXC_BAD_ACCESS":
- (NSFetchedResultsController *)fetchedResultsController {
// Set up the fetched results controller if needed.
if (fetchedResultsController == nil) {
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Setting" inManagedObjectContext:managedObjectContext];
[fetchRequest setEntity:entity];
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"key" ascending:YES];
NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor, nil];
[fetchRequest setSortDescriptors:sortDescriptors];
[fetchRequest setFetchLimit:1];
.
NSFetchedResultsController *aFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:managedObjectContext sectionNameKeyPath:nil cacheName:nil];
aFetchedResultsController.delegate = self;
self.fetchedResultsController = aFetchedResultsController;
[aFetchedResultsController release];
[fetchRequest release];
[sortDescriptor release];
[sortDescriptors release];
}
return fetchedResultsController;
}
I guess the pointer to the ManagedObjectContext is wrong, as a result from running in a different thread and memory-pool. So how do you create such an application if that is the issue), how do I get a reference to the original ManagedObjectContext format he thread?
[EDIT]
I also tried to use
iDomsAppDelegate *appDelegate = (iDomsAppDelegate *)[[UIApplication sharedApplication] delegate];
DataManager *data = [[DataManager alloc] initWithContext:appDelegate.managedObjectContext];
in doUpdateData (as hinted by other posts), but that gives the same result
Managed Object Contexts are not thread safe. Apple's guidelines indicate that you must have a separate instance of NSManagedObjectContext per thread.