Теперь это может звучать как моя предыдущая проблема / вопрос, но я изменил и попробовал несколько вещей, на которые были даны ответы в других моих вопросах, чтобы попытаться заставить это работать, но у меня все еще есть та же проблема.
Я наблюдаю свойство основных данных из подкласса NSManagedObject, и метод, который вызывается при изменении свойства, вызывает другой метод, но в этом методе он добавляет объекты Core Data, которые запускают метод KVO, который снова вызывает метод, и так далее. Или, кажется, я не слишком уверен в этом, потому что, кажется, происходит нечто иное, вот серия событий ...
- Я нажимаю кнопку синхронизации с iCal (это в IBAction с точно таким же кодом, который есть в методе syncKVO). Эта синхронизация работает нормально.
- Я добавляю объект в свой контурный вид. Все хорошо.
- Я изменяю его имя, которое вызывает объявление KVO (потому что я изменил свойство 'name'), которое синхронизируется с iCal. Работает отлично.
- Я удаляю только что добавленный объект, и каким-то образом он запускает объявление KVO (таким образом вызывая метод) и помещает меня в бесконечный цикл .
Теперь немного кода.
Код внутри подкласса NSManagedObject (называемый JGManagedObject)…
- (void) awakeFromFetch {
[self addObserver:[NSApp delegate] forKeyPath:@"name" options:0 context:nil];
}
- (void) awakeFromInsert {
[self addObserver:[NSApp delegate] forKeyPath:@"name" options:0 context:nil];
}
+ (void) addObserver{
[self addObserver:[NSApp delegate] forKeyPath:@"name" options:0 context:nil];
}
+ (void) removeObserver{
[self removeObserver:[NSApp delegate] forKeyPath:@"name"];
}
Декларация КВО (внутри Делегата приложения)…
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
if ([keyPath isEqualToString:@"name"]) {
[self performSelector:@selector(syncKVO:)];
}
}
Метод (также внутри делегата приложения)…
- (void)syncKVO:(id)sender {
NSManagedObjectContext *moc = [self managedObjectContext];
[syncButton setTitle:@"Syncing..."];
NSString *dateText = (@"Last Sync : %d", [NSDate date]);
[syncDate setStringValue:dateText];
NSEntityDescription *entityDescription = [NSEntityDescription
entityForName:@"projects" inManagedObjectContext:moc];
NSFetchRequest *request = [[[NSFetchRequest alloc] init] autorelease];
[request setEntity:entityDescription];
NSError *error = nil;
NSArray *array = [moc executeFetchRequest:request error:&error];
if (array == nil)
{
NSAlert *anAlert = [NSAlert alertWithError:error];
[anAlert runModal];
}
NSArray *namesArray = [array valueForKey:@"name"];
NSPredicate *predicate = [CalCalendarStore taskPredicateWithCalendars:[[CalCalendarStore defaultCalendarStore] calendars]];
NSArray *tasksNo = [[CalCalendarStore defaultCalendarStore] tasksWithPredicate:predicate];
NSArray *tasks = [tasksNo valueForKey:@"title"];
NSMutableArray *namesNewArray = [NSMutableArray arrayWithArray:namesArray];
[namesNewArray removeObjectsInArray:tasks];
NSLog(@"%d", [namesNewArray count]);
NSInteger *popIndex = [calenderPopup indexOfSelectedItem];
//Load the array
CalCalendarStore *store = [CalCalendarStore defaultCalendarStore];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, YES);
NSString *supportDirectory = [paths objectAtIndex:0];
NSString *fileName = [supportDirectory stringByAppendingPathComponent:@"oldtasks.plist"];
NSMutableArray *oldTasks = [[NSMutableArray alloc] initWithContentsOfFile:fileName];
[oldTasks removeObjectsInArray:namesArray];
NSLog(@"%d",[oldTasks count]);
//Use the content
NSPredicate* taskPredicate = [CalCalendarStore taskPredicateWithCalendars:[[CalCalendarStore defaultCalendarStore] calendars]];
NSArray* allTasks = [[CalCalendarStore defaultCalendarStore] tasksWithPredicate:taskPredicate];
// Get the calendar
CalCalendar *calendar = [[store calendars] objectAtIndex:popIndex];
// Note: you can change which calendar you're adding to by changing the index or by
// using CalCalendarStore's -calendarWithUID: method
// Loop, adding tasks
for(NSString *title in namesNewArray) {
// Create task
CalTask *task = [CalTask task];
task.title = title;
task.calendar = calendar;
// Save task
if(![[CalCalendarStore defaultCalendarStore] saveTask:task error:&error]) {
NSLog(@"Error");
// Diagnostic error handling
NSAlert *anAlert = [NSAlert alertWithError:error];
[anAlert runModal];
}
}
NSMutableArray *tasksNewArray = [NSMutableArray arrayWithArray:tasks];
[tasksNewArray removeObjectsInArray:namesArray];
NSLog(@"%d", [tasksNewArray count]);
for(NSString *title in tasksNewArray) {
NSManagedObjectContext *moc = [self managedObjectContext];
JGManagedObject *theParent =
[NSEntityDescription insertNewObjectForEntityForName:@"projects"
inManagedObjectContext:moc];
[theParent setValue:nil forKey:@"parent"];
// This is where you add the title from the string array
[theParent setValue:title forKey:@"name"];
[theParent setValue:[NSNumber numberWithInt:0] forKey:@"position"];
}
for(CalTask* task in allTasks)
if([oldTasks containsObject:task.title]) {
[store removeTask:task error:nil];
}
// Create a predicate for an array of names.
NSPredicate *mocPredicate = [NSPredicate predicateWithFormat:@"name IN %@", oldTasks];
[request setPredicate:mocPredicate];
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"name" ascending:YES];
[request setSortDescriptors:[NSArray arrayWithObject:sortDescriptor]];
// Execute the fetch request put the results into array
NSArray *resultArray = [moc executeFetchRequest:request error:&error];
if (resultArray == nil)
{
// Diagnostic error handling
NSAlert *anAlert = [NSAlert alertWithError:error];
[anAlert runModal];
}
// Enumerate through the array deleting each object.
// WARNING, this will delete everything in the array, so you may want to put more checks in before doing this.
for (JGManagedObject *objectToDelete in resultArray ) {
// Delete the object.
[moc deleteObject:objectToDelete];
}
//Save the array
[namesArray writeToFile:fileName atomically:YES];
[syncButton setTitle:@"Sync Now"];
NSLog(@"Sync Completed");
}
Что я пробовал ...
Фильтрация путей, вызывающих декларацию KVO, с помощью
if ([keyPath isEqualToString:@"name"]) {
…
}
Отсоединение и повторное подключение наблюдателей с помощью
[JGManagedObject removeObserver];
//and
[JGManagedObject addObserver];
но при этом он работает в первый раз, но останавливает метод во второй раз, говоря, что он не может удалить наблюдателя, потому что он не наблюдает, что не имеет смысла, потому что я снова добавил наблюдателя в первый раз. Вот почему я оставил этот код вне реального метода, иначе он остановился бы во второй синхронизации.
Я не уверен, что с этим происходит, я думаю, что все перепробовал. Что пошло не так?
Любая помощь будет принята с благодарностью.