方法/ IBAction陷入无限循环。仍然没有成功

时间:2009-10-24 11:32:33

标签: objective-c cocoa core-data infinite-loop

现在这可能听起来像我之前的问题/问题,但我已经改变并尝试了一些在我的其他问题中回答的事情,试图让它起作用,但我仍然遇到同样的问题。

我在NSManagedObject子类中观察核心数据属性,当属性更改时调用的方法调用另一个方法但在此方法中它添加了触发KVO方法的Core Data对象,该方法再次触发该方法等等。或者似乎,我不太确定,因为似乎发生了一些不同的事情,这是一系列事件......

  1. 我点击了一个与iCal同步的按钮(这在IBAction中使用的方法与syncKVO方法完全相同)。此同步工作正常。
  2. 我在大纲视图中添加了一个对象。一切都很好。
  3. 我更改了其名称,该名称触发了与iCal同步的KVO声明(因为我更改了'name'属性)。工作良好。
  4. 我删除了刚刚添加的对象,并以某种方式触发了KVO声明(从而触发了该方法),并将我置于无限循环
  5. 现在有些代码。

    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"];
    }
    

    KVO声明(在App代表内)......

    - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
        if ([keyPath isEqualToString:@"name"]) {
            [self performSelector:@selector(syncKVO:)];
        }
    }
    

    方法(也在App委托内)......

    - (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声明的Keypath
    if ([keyPath isEqualToString:@"name"]) {
    …
    } 
    

    使用

    分离和重新附加观察者
    [JGManagedObject removeObserver];
    //and
    [JGManagedObject addObserver];
    

    但是它第一次工作但第二次停止方法说它无法移除观察者,因为它没有观察,这没有意义,因为我第一次再次添加了观察者。这就是为什么我把这个代码从实际方法中删除,否则它会在第二次同步时停止。

    我不确定这是怎么回事,我想我已经尝试了一切。什么出错了?

    非常感谢任何帮助。

1 个答案:

答案 0 :(得分:3)

问题可能在这里:

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
if ([keyPath isEqualToString:@"name"]) {
    [self performSelector:@selector(syncKVO:)];
}

}

你调用syncKVO:每当“name”出现问题时,无论“name”实际发生了什么。我建议你开始使用对象,更改和上下文参数来确定刚刚发生的事情以及应采取的行动(如果有的话)。

顺便说一下,向应用代表添加大量内容并不是一种好习惯。您可能希望将所有这些同步内容放入适当的控制器类中,并在需要时调用[NSApp委托]。