Using Background Fetching with Core Data - objective-c

I am going through the "iOS 7 Programming Cookbook" and I can't seem to run the script based on the title of my question. Basically, I am trying to create some records in the background queue and then get the results in the main queue but nothing gets passed to the console when I run the code. Here are the methods used in the example. What am I missing here?
- (void) populateDatabase{
for (NSUInteger counter = 0; counter < 1000; counter++){
Person *person =
[NSEntityDescription
insertNewObjectForEntityForName:NSStringFromClass([Person class])
inManagedObjectContext:self.managedObjectContext];
person.firstName = [NSString stringWithFormat:#"First name %lu",
(unsigned long)counter];
person.lastName = [NSString stringWithFormat:#"Last name %lu",
(unsigned long)counter];
person.age = #(counter);
}
NSError *error = nil;
if ([self.managedObjectContext save:&error]){
NSLog(#"Managed to populate the database.");
} else {
NSLog(#"Failed to populate the database. Error = %#", error);
}
}
- (void) processPersons:(NSArray *)paramPersons{
for (Person *person in paramPersons){
NSLog(#"First name = %#, last name = %#, age = %ld",
person.firstName,
person.lastName,
(long)person.age.integerValue);
}
}
- (NSFetchRequest *) newFetchRequest{
NSFetchRequest *request = [[NSFetchRequest alloc]
initWithEntityName:
NSStringFromClass([Person class])];
request.fetchBatchSize = 20;
request.predicate =
[NSPredicate predicateWithFormat:#"(age >= 100) AND (age <= 200)"];
request.resultType = NSManagedObjectIDResultType;
return request;
}
- (BOOL) application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{
__weak NSManagedObjectContext *mainContext = self.managedObjectContext;
__weak AppDelegate *weakSelf = self;
__block NSMutableArray *mutablePersons = nil;
/* Set up the background context */
NSManagedObjectContext *backgroundContext =
[[NSManagedObjectContext alloc]
initWithConcurrencyType:NSPrivateQueueConcurrencyType];
backgroundContext.persistentStoreCoordinator =
self.persistentStoreCoordinator;
/* Issue a block on the background context */
[backgroundContext performBlock:^{
NSError *error = nil;
NSArray *personIds = [backgroundContext
executeFetchRequest:[weakSelf newFetchRequest]
error:&error];
if (personIds != nil && error == nil){
mutablePersons = [[NSMutableArray alloc]
initWithCapacity:personIds.count];
/* Now go on the main context and get the objects on that
context using their IDs */
dispatch_async(dispatch_get_main_queue(), ^{
for (NSManagedObjectID *personId in personIds){
Person *person = (Person *)[mainContext
objectWithID:personId];
[mutablePersons addObject:person];
}
[weakSelf processPersons:mutablePersons];
});
} else {
NSLog(#"Failed to execute the fetch request.");
}
}];
self.window = [[UIWindow alloc]
initWithFrame:[[UIScreen mainScreen] bounds]];
self.window.backgroundColor = [UIColor whiteColor];
ViewController *viewController = [[ViewController alloc] init];
self.window.rootViewController = viewController;
[self.window makeKeyAndVisible];
return YES;
}

Related

NSManagedObjectContext is nil in the UITableViewController class using CoreData

i need to display a few elements in a UITableViewController from CoreData, but the NSManagedObjectContext instance, called *managedObjectContext, is nil when the app launching.
This is my UITableViewController.h
#interface TableViewController : UITableViewController
#property(nonatomic,strong) NSArray *listaElementi;
#property (readonly, strong, nonatomic) NSManagedObjectContext *managedObjectContext; //si occupa di gestire come sono strutturate le entity
#end
This is my UITableViewController.m
- (void)viewDidLoad {
[super viewDidLoad];
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription
entityForName:#"Stato" inManagedObjectContext:managedObjectContext];
[fetchRequest setEntity:entity];
NSError *error;
self.listaElementi = [managedObjectContext executeFetchRequest:fetchRequest error:&error];
self.title = #"Stati";
Finally this is my AppDelegate.m
#synthesize managedObjectContext = _managedObjectContext;
#synthesize managedObjectModel = _managedObjectModel;
#synthesize persistentStoreCoordinator = _persistentStoreCoordinator;
- (NSManagedObjectModel *)managedObjectModel {
// The managed object model for the application. It is a fatal error for the application not to be able to find and load its model.
if (_managedObjectModel != nil) {
return _managedObjectModel;
}
NSURL *modelURL = [[NSBundle mainBundle] URLForResource:#"Model" withExtension:#"momd"]; //SETTARE BENE IL MODELLO
_managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
return _managedObjectModel;
}
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator {
// The persistent store coordinator for the application. This implementation creates and return a coordinator, having added the store for the application to it.
if (_persistentStoreCoordinator != nil) {
return _persistentStoreCoordinator;
}
// Create the coordinator and store
_persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];
NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:#"Database.sqlite"];
NSError *error = nil;
NSString *failureReason = #"There was an error creating or loading the application's saved data.";
if (![_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:&error]) {
// Report any error we got.
NSMutableDictionary *dict = [NSMutableDictionary dictionary];
dict[NSLocalizedDescriptionKey] = #"Failed to initialize the application's saved data";
dict[NSLocalizedFailureReasonErrorKey] = failureReason;
dict[NSUnderlyingErrorKey] = error;
error = [NSError errorWithDomain:#"YOUR_ERROR_DOMAIN" code:9999 userInfo:dict];
// Replace this 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]);
abort();
}
return _persistentStoreCoordinator;
}
- (NSManagedObjectContext *)managedObjectContext {
// Returns the managed object context for the application (which is already bound to the persistent store coordinator for the application.)
if (_managedObjectContext != nil) {
return _managedObjectContext;
}
NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
if (!coordinator) {
return nil;
}
_managedObjectContext = [[NSManagedObjectContext alloc] init];
[_managedObjectContext setPersistentStoreCoordinator:coordinator];
return _managedObjectContext;
}
Could you help me? When I created the project I don't checked the adding core data box , but I implemented all manually and I just created the model and I just Inserted a few element into the Database, is a possible cause of the problem?
Try this in viewDidLoad
- (void)viewDidLoad {
[super viewDidLoad];
AppDelegate *delgate = (AppDelegate *)[[UIApplication
sharedApplication]delegate];
self.managedObjectContext = delegate.managedObjectContext;
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription
entityForName:#"Stato" inManagedObjectContext:self.managedObjectContext];
[fetchRequest setEntity:entity];
NSError *error;
self.listaElementi = [self.managedObjectContext executeFetchRequest:fetchRequest error:&error];
}

Check Api Version from web server for update core data

Thanks in advance for the help and be understanding if i write strange things i'm new in objective-c language.
I get json from web service and trying to store all in core-data so in case of network status off can i run app whit saved data.
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
self.managedObjectContext = [self managedObjectContextWithName:#"CoreData"];
NSMutableArray * competition = [self.jsonCompetition objectForKey:#"Competition"];
NSMutableDictionary * competizione = [[NSMutableDictionary alloc] init];
for (int i = 0; i< competition.count; i++) {
NSManagedObject * competion = [NSEntityDescription
insertNewObjectForEntityForName:#"Competition"
inManagedObjectContext:self.managedObjectContext];
competizione = [competition objectAtIndex:i];
[competion setValue:[competizione objectForKey:#"id"] forKeyPath:#"id"];
[competion setValue:[competizione objectForKey:#"name"] forKeyPath:#"name"];
[competion setValue:[competizione objectForKey:#"region"] forKeyPath:#"region"];
NSError *error;
if (![self.managedObjectContext save:&error]) {
NSLog(#"Errore: %#", [error localizedDescription]);
}
}
NSError *errore;
if (!errore) {
// NSLog(#"%#",_jsonDict);
} else {
NSLog(#"ERROR!");
}
[self.managedObjectContext save:&errore];
Reachability *reachability = [Reachability reachabilityForInternetConnection];
NetworkStatus networkStatus = [reachability currentReachabilityStatus];
if (networkStatus == ReachableViaWWAN) {
} else if (networkStatus == ReachableViaWiFi) {
NSData *data = [self callWS];
NSError *errore;
self.jsonCompetition = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions
error:&errore];
self.managedObjectContext = [self managedObjectContextWithName:#"CoreData"];
NSMutableArray * competition = [self.jsonCompetition objectForKey:#"Competition"];
NSMutableDictionary * competizione = [[NSMutableDictionary alloc] init];
for (int i = 0; i< competition.count; i++) {
NSManagedObject * competion = [NSEntityDescription
insertNewObjectForEntityForName:#"Competition"
inManagedObjectContext:self.managedObjectContext];
competizione = [competition objectAtIndex:i];
[competion setValue:[competizione objectForKey:#"id"] forKeyPath:#"id"];
[competion setValue:[competizione objectForKey:#"name"] forKeyPath:#"name"];
[competion setValue:[competizione objectForKey:#"region"] forKeyPath:#"region"];
if (![self.managedObjectContext save:&errore]) {
NSLog(#"Errore: %#", [errore localizedDescription]);
}
}
[self.managedObjectContext save:&errore];
if (!error) {
// NSLog(#"%#",_jsonDict);
} else {
NSLog(#"ERROR!");
}
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entityCompetizione = [NSEntityDescription
entityForName:#"Competition" inManagedObjectContext:self.managedObjectContext];
[fetchRequest setEntity:entityCompetizione];
NSArray *arrayCompetizioni = [self.managedObjectContext executeFetchRequest:fetchRequest error:&errore];
} else {
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entityCompetizione = [NSEntityDescription
entityForName:#"Competition" inManagedObjectContext:self.managedObjectContext];
[fetchRequest setEntity:entityCompetizione];
NSArray *arrayCompetizioni = [self.managedObjectContext executeFetchRequest:fetchRequest error:&errore];
}
FirstViewController * fVC = [[FirstViewController alloc]initWithNibName:#"FirstViewController" bundle:nil];
self.window.rootViewController = fVC;
[self.window makeKeyAndVisible];
return YES;
In json i have a key whit ApiVersion,there is a way to check if core-data need to be updated whit the new version of json (in case of network status is on )??
thanks
You save the previous ApiVersion to NSUserDefaults:
NSNumber *currentApiVersion = ...; //You get the version here from JSON
[[NSUserDefaults standardUserDefaults] setObject:currentApiVersion forKey:#"ApiVersion"];
When new data arrives, you compare with the saved value:
NSNumber *currentApiVersion = ...; //You get the version here from the JSON
NSNumber *previousApiVersion = [[NSUserDefaults standardUserDefaults] objectForKey:#"ApiVersion"];
if (![currentApiVersion isEqualToNumber:previousApiVersion]) {
//Update the stored version
[[NSUserDefaults standardUserDefaults] setObject:currentApiVersion forKey:#"ApiVersion"];
//The Api Version is different.
}

Some data not staying in Core Data

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.

NSManagedObjectContext crashing when accessed on external thread

I'm currently having a threading issue with the managedObjectContext within my application. Currently, I have a background thread running that MUST be in the background, but accesses the managedObjectContext at the same time. Another ViewController calls on the method processAllApplications shown below that then calls checkCompletedApplicationsFor24HourExpiration which then calls getAppsWithStatus. The thread seems to be currently locked causing this operation to halt where the warning below is. I need a way to process this through and am quite a noob when it comes to Core Data. Would anyone be able to advise. I was reading that I may have to create multiple instances of my managedObject and merge them. How would I go about that if that is the case?
AppDelegate:
- (NSManagedObjectContext *)managedObjectContext
{
[__managedObjectContext lock];
if (__managedObjectContext != nil) {
[__managedObjectContext unlock];
return __managedObjectContext;
}
NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
if (coordinator != nil) {
__managedObjectContext = [[NSManagedObjectContext alloc] init];
[__managedObjectContext setPersistentStoreCoordinator:coordinator];
}
[__managedObjectContext unlock];
return __managedObjectContext;
}
- (NSMutableArray*)getAppsWithStatus:(int)intStatus {
NSLog(#"%i on main thread getAppsWithStatus", [NSThread currentThread].isMainThread);
NSEntityDescription *entityDescription = [NSEntityDescription entityForName:#"Application" inManagedObjectContext:self.managedObjectContext];
NSFetchRequest *request = [[NSFetchRequest alloc] init];
[request setEntity:entityDescription];
// Set example predicate and sort orderings...
NSNumber *status = [NSNumber numberWithInt:intStatus];
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"status = %# && username = %#", status, [[NSUserDefaults standardUserDefaults] objectForKey:#"username"]];
#warning FAILS HERE INTO ABYSS
[request setPredicate:predicate];
NSError *error = nil;
NSMutableArray* applications = [[NSMutableArray alloc] initWithArray:[self.managedObjectContext executeFetchRequest:request error:&error]];
for (Application* eachApp in applications)
eachApp.applicationNumber = nil;
[self saveDB];
return applications;
}
- (void)processAllApplications:(id)userInfo {
[self.processApplicationsLock lock];
if ([[NSUserDefaults standardUserDefaults] objectForKey:#"username"] == nil) return; // Not logged in
NSLog(#"processing");
[self checkCompletedApplicationsFor24HourExpiration];
[self alertFor12HourCompletedApplications];
[self alertForExpiredDraftApplications];
if ([DeleteAllDraftApplicationsForCurrentApplicationYear isSatisifiedByDate:[DateTimeFactory currentApplicationDate]]) {
[self deleteExpiredApps];
}
[self performSelector:#selector(sendApplications:) withObject:nil afterDelay:3];
[self.processApplicationsLock unlock];
}
- (void)checkCompletedApplicationsFor24HourExpiration {
NSLog(#"OutboxSender - (void)checkCompletedApplicationsFor24HourExpiration");
NSLog(#"%i on main thread checkCompletedApplicationsFor24HourExpiration", [NSThread currentThread].isMainThread);
NSArray* completedApps = [self getAppsWithStatus:STATUS_COMPLETED];
NSDate* targetDate = [self offsetDate:[DateTimeFactory currentApplicationDate] withDay:-1 withMonth:0 withHour:0];
for (Application* theApplication in completedApps) {
if ([MoveCompletedApplicationToDraftApplicationSpec isSatisfiedByApplication:theApplication cutOffDate:targetDate]) {
NSLog(#"Sending To draft with date: %#", theApplication.submittedDate);
theApplication.status = [NSNumber numberWithInt:STATUS_DRAFT];
[self deleteSignatures:theApplication];
}
}
NSString* message = [NSString stringWithFormat:#"%i completed application/s have been sent to drafts", [completedApps count]];
echo_Alert(#"", message);
[self saveDB];
}
create separate managed object context
+(NSManagedObjectContext *)getManagedObjectContext
{
NSManagedObjectContext *managedObjectContext;
#try {
NSPersistentStoreCoordinator * coordinator = [self persistentStoreCoordinator];
if (coordinator != nil) {
managedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
[managedObjectContext setPersistentStoreCoordinator: coordinator];
}
}
#catch (NSException *exception) {
NSLog(#"Exception occur %#",exception);
}
return managedObjectContext;
Use this separate managed object context in your fetching method,
- (NSMutableArray*)getAppsWithStatus:(int)intStatus {
NSMutableArray * mutableObjects;
NSLog(#"%i on main thread getAppsWithStatus", [NSThread currentThread].isMainThread);
NSEntityDescription *entityDescription = [NSEntityDescription entityForName:#"Application" inManagedObjectContext:[self getManagedObjectContext]]; // Here use separate managed object context
NSFetchRequest *request = [[NSFetchRequest alloc] init];
[request setEntity:entityDescription];
// Set example predicate and sort orderings...
NSNumber *status = [NSNumber numberWithInt:intStatus];
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"status = %# && username = %#", status, [[NSUserDefaults standardUserDefaults] objectForKey:#"username"]];
#warning FAILS HERE INTO ABYSS
[request setPredicate:predicate];
NSError *error = nil;
NSMutableArray* applications = [[NSMutableArray alloc] initWithArray:[[self getManagedObjectContext] executeFetchRequest:request error:&error]];
NSMutableArray * resultedArray = [applications mutableCopy];
NSMutableArray * objectIds = [[NSMutableArray alloc] initWithCapacity:[resultedArray count]];
for (NSManagedObject *obj in resultedArray) {
[objectIds addObject:obj.objectID];
}
mutableObjects = [[NSMutableArray alloc] initWithCapacity:[objectIds count]];
for (NSManagedObjectID * objectID in objectIds) {
NSManagedObject * obj = [self.managedObjectContext
objectWithID:objectID]; // Here use self.managedObjectContext in which you already created.
[mutableObjects addObject:obj];
}
for (Application* eachApp in mutableObjects)
eachApp.applicationNumber = nil;
[self saveDB];
return mutableObjects;
}

NSNotificationCenter notifications not sent/received

// Question was answered, basicly I should sleep more / code less :)
When my app starts i first load a splash screen, this splashscreen will start a dataDownload when the screen itself is done loading:
Splash.m
#implementation Splash
- (id) init
{
self = [super init];
_lblFunds = [[UILabel alloc] initWithFrame:CGRectMake(350, 330, 324,28)];
_lblFunds.numberOfLines = 1;
[_lblFunds setFont:[UIFont systemFontOfSize:24.0]];
[_lblFunds setTextAlignment: UITextAlignmentCenter];
[_lblFunds setText:#".. Fondsen .."];
[self.view addSubview:_lblFunds];
_lblObjects = [[UILabel alloc] initWithFrame:CGRectMake(350, 360, 324,28)];
_lblObjects.numberOfLines = 1;
[_lblObjects setFont:[UIFont systemFontOfSize:24.0]];
[_lblObjects setTextAlignment: UITextAlignmentCenter];
[_lblObjects setText:#".. Vastgoed Objecten .."];
[self.view addSubview:_lblObjects];
_lblCustomers = [[UILabel alloc] initWithFrame:CGRectMake(350, 390, 324,28)];
_lblCustomers.numberOfLines = 1;
[_lblCustomers setFont:[UIFont systemFontOfSize:24.0]];
[_lblCustomers setTextAlignment: UITextAlignmentCenter];
[_lblCustomers setText:#".. Clienten .."];
[self.view addSubview:_lblCustomers];
return self;
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(fundsLoaded) name:#"FundsDone" object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(customersLoaded) name:#"CustomersDone" object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(objectsLoaded) name:#"ObjectsDone" object:nil];
}
- (void) fundsLoaded
{
[_lblFunds setText:[NSString stringWithFormat:#"Fondsen geladen: %d",[[DataManager sharedInstance] fundsCount]]];
}
- (void) objectsLoaded
{
[_lblObjects setText:[NSString stringWithFormat:#"Vastgoed Objecten geladen: %d",[[DataManager sharedInstance] objectsCount]]];
}
- (void) customersLoaded
{
[_lblCustomers setText:[NSString stringWithFormat:#"Clienten geladen: %d",[[DataManager sharedInstance] customersCount]]];
}
- (void) viewDidLoad
{
[super viewDidLoad];
[[DataManager sharedInstance] getData];
}
- (void)viewDidUnload
{
[super viewDidUnload];
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
// Return YES for supported orientations
return YES;
}
#end
The DataManager will then proceed to use its instance of DataLoader to load and parse the data in a seperate thread, whenever data is parsed and stored away a Notification is sent from the DataLoader. If worked with the Notifications a lot before but this time it just will not work and I cannot seem to figure out why not. There is no error or anything, but the functions as set in the observers are never called. Any ideas on what is wrong are very much welcome, I have read quite a few threads on here, and other sites but haven't found my answer yet.
DataManager.m
#implementation DataManager
static DataManager* _dataManager = nil;
static DataLoader *_dataLoader = nil;
static bool _dataLoaded = FALSE;
- (int) fundsCount
{
return _dataLoader.funds_count;
}
- (int) objectsCount
{
return _dataLoader.objects_count;
}
- (int) customersCount
{
return _dataLoader.customers_count;
}
+ (DataManager *) sharedInstance{
#synchronized([DataManager class])
{
if(!_dataManager)
{
_dataManager = [[super alloc] init];
_dataLoader = [[DataLoader alloc] init];
}
return _dataManager;
}
return nil;
}
- (void) loadDataSucces
{
_dataLoaded = TRUE;
}
- (void) _getData
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
if(_dataLoader)
{
[_dataLoader loadData];
} else
{
NSLog(#"DataLoader not initialized");
}
[pool drain];
}
- (void) getData
{
[NSThread detachNewThreadSelector:#selector(_getData) toTarget:self withObject:nil];
}
#end
DataLoader.m
- (void) parseData: (NSString *) jsonString
{
NSError *err;
SBJsonParser *parser = [[SBJsonParser alloc] init];
id object = [parser objectWithString:jsonString error:&err];
[jsonString release];
if (!object) {
} else {
//funds
id funds = [object objectForKey:#"fondsen"];
[self deleteAllEntitiesOfType:#"Fund"];
int nr = 0;
for (NSDictionary *i in funds)
{
NSString *naam = [i objectForKey:#"naam"];
if([naam length] > 2)
{
NSManagedObjectContext *context = [(CatalogusAppDelegate *)[[UIApplication sharedApplication] delegate] managedObjectContext];
Fund *f = [NSEntityDescription insertNewObjectForEntityForName:#"Fund" inManagedObjectContext: context];
NSString *integertje = [i objectForKey:#"oid"];
int in = [integertje integerValue];
[f setOid: [NSNumber numberWithInt: in ]];
[f setNaam: naam];
NSError *error = nil;
if( ![context save: &error ])
{
NSLog(#"Error: %#", [[error userInfo] valueForKey:#"ErrorString"]);
} else
{
nr++;
}
}
}
funds_count = nr;
[[NSNotificationCenter defaultCenter] postNotificationName:#"FundsDone" object:nil];
//objects
if( true )
{
id objects = [object objectForKey:#"vastgoedobjecten"];
[self deleteAllEntitiesOfType:#"Object"];
nr = 0;
NSManagedObjectContext *context = [(CatalogusAppDelegate *)[[UIApplication sharedApplication] delegate] managedObjectContext];
for (NSDictionary *i in objects)
{
Object *o = [NSEntityDescription insertNewObjectForEntityForName:#"Object" inManagedObjectContext: context];
[o setFondsOid:[NSNumber numberWithInt: [ [i objectForKey:#"fondsOid"] integerValue] ]];
[o setOid: [NSNumber numberWithInt: [ [i objectForKey:#"oid"] integerValue] ]];
[o setAdres:[i objectForKey:#"adres"]];
[o setPostcode:[i objectForKey:#"postcode"]];
[o setPlaats: [ i objectForKey:#"plaats"]];
[o setProvincie:[i objectForKey:#"provincie"]];
[o setStatus:[i objectForKey:#"status"]];
[o setSegment:[i objectForKey:#"segment"]];
[o setOppervlakte:[NSNumber numberWithInt: [ [i objectForKey:#"oppervlakte"] integerValue] ]];
[o setBelangrijksteHuurder:[i objectForKey:#"belangrijksteHuurder"]];
[o setWeging:[i objectForKey:#"weging"]];
[o setLongitude:[NSNumber numberWithDouble: [ [i objectForKey:#"longitude"] doubleValue] ]];
[o setLatitude:[NSNumber numberWithDouble: [ [i objectForKey:#"latitude"] doubleValue] ]];
NSError *error = nil;
if( ![context save: &error ])
{
NSLog(#"Error: %#", [[error userInfo] valueForKey:#"ErrorString"]);
} else
{
nr++;
}
}
objects_count = nr;
NSLog(#"ObjectsLoaded");
[[NSNotificationCenter defaultCenter] postNotificationName:#"ObjectsDone" object:nil];
}
//customers
if( true )
{
id custs = [object objectForKey:#"klanten"];
[self deleteAllEntitiesOfType:#"Customer"];
nr = 0;
NSManagedObjectContext *context = [(CatalogusAppDelegate *)[[UIApplication sharedApplication] delegate] managedObjectContext];
for (NSDictionary *i in custs)
{
Customer *c = [NSEntityDescription insertNewObjectForEntityForName:#"Customer" inManagedObjectContext: context];
[c setOid: [NSNumber numberWithInt: [ [i objectForKey:#"oid"] integerValue] ]];
[c setFondsOid:[NSNumber numberWithInt: [ [i objectForKey:#"fondsOid"] integerValue] ]];
[c setNaam: [i objectForKey:#"naam"]];
NSError *error = nil;
if( ![context save: &error ])
{
NSLog(#"Error: %#", [[error userInfo] valueForKey:#"ErrorString"]);
} else
{
nr++;
}
}
customers_count = nr;
[[NSNotificationCenter defaultCenter] postNotificationName:#"CustomersDone" object:nil];
}
}
[[NSNotificationCenter defaultCenter] postNotificationName:#"DataReady" object:nil];
}
- (void) loadData{
NSString *urlString = #"URL";
NSDate *startDownload = [NSDate date];
NSURLRequest *theRequest=[NSURLRequest requestWithURL:[NSURL URLWithString:urlString]
cachePolicy:NSURLRequestUseProtocolCachePolicy
timeoutInterval:60.0];
NSURLResponse *response = nil;
NSError *error = nil;
NSData *dataFeed = [NSURLConnection sendSynchronousRequest:theRequest returningResponse:&response error:&error];
if(error){
NSString *d = [ error description ];
NSLog(#"error: %#",d);
} int bytes = [dataFeed length];
NSDate *endDownload = [NSDate date];
NSString *data = [[NSString alloc] initWithData:[NSData decompress:dataFeed] encoding:NSStringEncodingConversionExternalRepresentation];
int string = [data length];
NSDate *endDecompress = [NSDate date];
NSLog(#"Download data: %f - Decompress: %f - BytesDownloaded: %d", [endDownload timeIntervalSinceDate:startDownload], [endDecompress timeIntervalSinceDate:endDownload], bytes);
[[NSNotificationCenter defaultCenter] postNotificationName:#"DownloadDone" object:nil];
[self parseData:data];
}
In init, you should put your registration code BEFORE the return statement. Otherwise it will never run.
Cheers!