quartz使用JobStoreTX时为啥触发器不能定时触发
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了quartz使用JobStoreTX时为啥触发器不能定时触发相关的知识,希望对你有一定的参考价值。
参考技术A 首先你应该使用的是持久化的quartz,所有定时任务的情况都是保存在数据库表总的,每次启动时,scheduler容器都是按照qrtz_triggers等表内存储的信息来执行定时任务(主要包括cron表达式,上一次执行时间) 你只要修改持久化表中相应的表达式即可为啥删除对象时不触发 NSFetchedResultsChangeDelete?
【中文标题】为啥删除对象时不触发 NSFetchedResultsChangeDelete?【英文标题】:Why is NSFetchedResultsChangeDelete not triggered when object is deleted?为什么删除对象时不触发 NSFetchedResultsChangeDelete? 【发布时间】:2012-05-18 07:32:42 【问题描述】:插入 (NSFetchedResultsChangeInsert
) 正在我的后台线程工作,来自同一个线程,使用相同的 managedObjectContext 保存合并通知,因此得到正确保存,删除不起作用(表格视图中可见的删除动画因此不起作用) .
已更新,现在显示有问题的 SchedulesViewController.m 的所有代码:
#import "SchedulesViewController.h"
#import "CustomScheduleTableViewCell.h"
#import <QuartzCore/QuartzCore.h>
#import "ViewScheduleViewController.h"
@implementation SchedulesViewController
NSIndexPath *deleteActionIndexPath;
@synthesize fetchedResultsController, managedObjectContext;
- (id)initWithStyle:(UITableViewStyle)style
self = [super initWithStyle:style];
if (self)
// Custom initialization
return self;
- (void)didReceiveMemoryWarning
// Releases the view if it doesn't have a superview.
[super didReceiveMemoryWarning];
// Release any cached data, images, etc that aren't in use.
#pragma mark - View lifecycle
- (void)viewDidLoad
[super viewDidLoad];
if (managedObjectContext == nil)
managedObjectContext = [(AppDelegate *)[[UIApplication sharedApplication] delegate] managedObjectContext];
self.title = @"Schema's";
// Uncomment the following line to display an Edit button in the navigation bar for this view controller.
self.navigationItem.leftBarButtonItem = self.editButtonItem;
NSError *error = nil;
if (![[self fetchedResultsController] performFetch:&error])
/*
Replace this implementation with code to handle the error appropriately.
abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development. If it is not possible to recover from the error, display an alert panel that instructs the user to quit the application by pressing the Home button.
*/
NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
abort();
- (void)viewDidUnload
[super viewDidUnload];
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
//storedReminderSchedules = nil;
//context = nil;
- (void)viewWillAppear:(BOOL)animated
[super viewWillAppear:animated];
NSLog(@"Schedules viewWillAppear");
- (void)viewDidAppear:(BOOL)animated
[super viewDidAppear:animated];
- (void)viewWillDisappear:(BOOL)animated
[super viewWillDisappear:animated];
- (void)viewDidDisappear:(BOOL)animated
[super viewDidDisappear:animated];
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
return YES;
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
return [[fetchedResultsController sections] count];
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
// check if we really have any sections in the managed object:
//if (!fetchedResultsController.sections.count) return @"Persoonlijk";
id <NSFetchedResultsSectionInfo> sectionInfo = [[fetchedResultsController sections] objectAtIndex:section];
return [sectionInfo name];
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
// check if we really have any sections in the managed object:
//if (!fetchedResultsController.sections.count) return 0;
id <NSFetchedResultsSectionInfo> sectionInfo = [[fetchedResultsController sections] objectAtIndex:section];
return [sectionInfo numberOfObjects];
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
static NSString *CellIdentifier = @"ScheduleCell";
CustomScheduleTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
[self configureCell:cell atIndexPath:indexPath];
return cell;
// Override to support conditional editing of the table view.
- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath
return YES;
- (void)configureCell:(CustomScheduleTableViewCell*)cell atIndexPath:(NSIndexPath*)indexPath
// Configure the cell.
ReminderSchedule *reminderSchedule = [fetchedResultsController objectAtIndexPath:indexPath];
cell.name.text = reminderSchedule.name;
#pragma mark - Table view delegate
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
if ([[[[fetchedResultsController sections] objectAtIndex:indexPath.section] name] hasPrefix:@"Dr."])
ViewScheduleViewController *controller = [[ViewScheduleViewController alloc]init];
controller.reminderSchedule = [self.fetchedResultsController objectAtIndexPath:[self.tableView indexPathForSelectedRow]];
controller.context = [fetchedResultsController managedObjectContext];
[self.navigationController pushViewController:controller animated:YES];
else
[self performSegueWithIdentifier:@"EditSchedule" sender:self];
- (UITableViewCellEditingStyle)tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath
return UITableViewCellEditingStyleDelete;
#pragma mark - ModifyScheduleViewControllerDelegate
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
if ([segue.identifier isEqualToString:@"AddSchedule"])
[TestFlight passCheckpoint:@"Add Schedule"];
// Get reference to the destination view controller
UINavigationController *navigationController = segue.destinationViewController;
ModifyScheduleViewController *controller = [[navigationController viewControllers] objectAtIndex:0];
controller.delegate = self;
controller.fetchedResultsController = self.fetchedResultsController;
[controller.navigationItem.rightBarButtonItem setEnabled:NO];
else if ([segue.identifier isEqualToString:@"EditSchedule"])
[TestFlight passCheckpoint:@"Edit Schedule"];
// Get reference to the destination view controller
UINavigationController *navigationController = segue.destinationViewController;
ModifyScheduleViewController *controller = [[navigationController viewControllers] objectAtIndex:0];
controller.delegate = self;
controller.fetchedResultsController = self.fetchedResultsController;
controller.reminderSchedule = [self.fetchedResultsController objectAtIndexPath:[self.tableView indexPathForSelectedRow]];
#pragma mark -
#pragma mark Fetched results controller
- (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:@"ReminderSchedule" inManagedObjectContext:managedObjectContext];
[fetchRequest setEntity:entity];
// Set the batch size to a suitable number.
[fetchRequest setFetchBatchSize:20];
// Edit the sort key as appropriate.
NSSortDescriptor *sortDescriptorName = [[NSSortDescriptor alloc] initWithKey:@"name" ascending:NO];
NSSortDescriptor *sortDescriptorSection = [[NSSortDescriptor alloc] initWithKey:@"sectionName" ascending:YES];
NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptorSection,sortDescriptorName, 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:managedObjectContext sectionNameKeyPath:@"sectionName" cacheName:@"Root"];
aFetchedResultsController.delegate = self;
self.fetchedResultsController = aFetchedResultsController;
return fetchedResultsController;
- (void)controller:(NSFetchedResultsController *)controller didChangeSection:(id <NSFetchedResultsSectionInfo>)sectionInfo
atIndex:(NSUInteger)sectionIndex forChangeType:(NSFetchedResultsChangeType)type
NSLog(@"didChangeSection");
switch(type)
case NSFetchedResultsChangeUpdate:
[self.tableView reloadData];
break;
case NSFetchedResultsChangeInsert:
[self.tableView insertSections:[NSIndexSet indexSetWithIndex:sectionIndex] withRowAnimation:UITableViewRowAnimationFade];
break;
case NSFetchedResultsChangeDelete:
[self.tableView deleteSections:[NSIndexSet indexSetWithIndex:sectionIndex] withRowAnimation:UITableViewRowAnimationFade];
break;
// Notifies the delegate that section and object changes are about to be processed and notifications will be sent.
- (void)controllerWillChangeContent:(NSFetchedResultsController *)controller
[self.tableView beginUpdates];
- (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject
atIndexPath:(NSIndexPath *)indexPath
forChangeType:(NSFetchedResultsChangeType)type
newIndexPath:(NSIndexPath *)newIndexPath
switch (type)
case NSFetchedResultsChangeInsert:
[self.tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath]
withRowAnimation:UITableViewRowAnimationFade];
break;
case NSFetchedResultsChangeUpdate:
[self configureCell:(CustomScheduleTableViewCell *)[self.tableView cellForRowAtIndexPath:indexPath]
atIndexPath:indexPath];
break;
case NSFetchedResultsChangeDelete:
[self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath]
withRowAnimation:UITableViewRowAnimationFade];
break;
case NSFetchedResultsChangeMove:
[self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath]
withRowAnimation:UITableViewRowAnimationFade];
[self.tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath]
withRowAnimation:UITableViewRowAnimationFade];
break;
default:
break;
- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller
[self.tableView endUpdates];
- (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation duration:(NSTimeInterval)duration
[self.tableView reloadData];
@end
更新 额外信息:
对象的插入和删除发生在同一个线程中,它们使用相同的 managedObjectContext 并使用相同的保存存储。实际上,首先插入对象,然后删除其他对象,然后保存一个。
我正在使用触发 AppDelegate 中的保存合并的 NSManagedObjectContextDidSaveNotification 进行保存。
更新 更多代码:
AppDelegate.m
- (void)saveContext
NSError *error = nil;
NSManagedObjectContext *managedObjectContext = self.managedObjectContext;
if (managedObjectContext != nil)
if ([managedObjectContext hasChanges] && ![managedObjectContext save:&error])
// Replace this implementation with code to handle the error appropriately.
// abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
abort();
-(void)mergeChanges:(NSNotification *)saveNotification
NSLog(@"Merging and saving");
if ([NSThread isMainThread])
[self.managedObjectContext mergeChangesFromContextDidSaveNotification:saveNotification];
else
[self performSelectorOnMainThread:@selector(mergeChanges:) withObject:saveNotification waitUntilDone:NO];
BacgroundThread.m
AppDelegate *theDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
NSNotificationCenter *notify = [NSNotificationCenter defaultCenter];
NSManagedObjectContext *newMoc = [[NSManagedObjectContext alloc] init];
[newMoc setPersistentStoreCoordinator:[theDelegate persistentStoreCoordinator]];
//为了说明而缩短插入部分(插入效果很好)
ReminderSchedule *reminderSchedule = [NSEntityDescription insertNewObjectForEntityForName:[entity name] inManagedObjectContext:newMoc];
//实际删除段码
if ([jsonDict objectForKey:@"deletedSchedules"] != nil)
NSArray *deletedSchedules = [jsonDict objectForKey:@"deletedSchedules"];
for (int i = 0; i < [deletedSchedules count]; i++)
NSInteger externalScheduleID = [[deletedSchedules objectAtIndex:i] intValue];
NSLog(@"Removing schedule %d", externalScheduleID);
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:@"ReminderSchedule" inManagedObjectContext:newMoc];
[fetchRequest setEntity:entity];
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"externalScheduleID == %d", externalScheduleID];
[fetchRequest setPredicate:predicate];
NSError *error = nil;
NSArray *result = [newMoc executeFetchRequest:fetchRequest error:&error];
for (NSManagedObject *managedObject in result)
[newMoc deleteObject:managedObject];
//插入删除后保存
NSError *saveError = nil;
if (![newMoc save:&saveError])
NSLog(@"Whoops, couldn't save: %@", [saveError localizedDescription]);
[[NSNotificationCenter defaultCenter] removeObserver:theDelegate];
更新 进行插入和删除,然后保存作品。自己进行插入是有效的。自己删除是不行的。
【问题讨论】:
其他回调(插入、更新)是否正常工作? 是的,插入工作正常。调用委托函数并插入动画效果很好。 我假设删除本身不起作用(删除的记录仍然显示在数据库中)。贴出相关代码。 删除工作正常。当应用程序重新启动时,带有 NSFetchResultsController 的 viewController 被重新初始化,条目消失了。 向我们展示您如何删除以及如何合并更改的代码... 【参考方案1】:确保 NSNotificationCenter 始终使用 NSManagedObjectContextDidSaveNotification 注册,而不仅仅是在需要插入内容时。
【讨论】:
【参考方案2】:确保self.fetchResultsController.delegate = self;
在您的viewDidLoad
方法中。
【讨论】:
委托设置为自己。否则不会使用 insert 调用委托方法。以上是关于quartz使用JobStoreTX时为啥触发器不能定时触发的主要内容,如果未能解决你的问题,请参考以下文章
SpringBoot 1.5.x 集成 Quartz 任务调度框架