如何在NSManagedObject子类中添加通知观察器以避免调用无法识别的选择器

时间:2014-03-11 11:44:21

标签: objective-c cocoa core-data

我一直遇到保存托管对象(在后台线程中)的问题,导致调用无法识别的选择器,这似乎与我处理NSManagedObjectContextObjectsDidChangeNotification观察的方式有关。间歇性地,它将失败-[NSFetchRequest myManagedObjectContextDidChange:]: unrecognized selector sent to instance。它并不总是NSFetchRequest,有时它是NSKeyValueObservance或未指定的,这让我相信观察者在托管对象被释放后仍然存在。

我将观察者添加到NSManagedObjectContextObjectsDidChangeNotification并将其移除,如下所示。那有什么不对吗?

@interface Foo ()
@property (assign, nonatomic, getter = isObserving) BOOL observing;
@end

@implementation Foo
@synthesize observing = _observing;

- (void)awakeFromInsert {
    [super awakeFromInsert];

    self.addedDate = [NSDate date];
    self.modificationDate = [self.addedDate copy];

    [self commonAwake];
}

- (void)awakeFromFetch {
    [super awakeFromFetch];
    [self commonAwake];
}

- (void)awakeFromSnapshotEvents:(NSSnapshotEventType)flags {
    [super awakeFromSnapshotEvents:flags];
    [self commonAwake];
}

- (void)commonAwake
{
    if (self.isObserving) return;

    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(myManagedObjectContextDidChange:)
                                                 name:NSManagedObjectContextObjectsDidChangeNotification
                                               object:self.managedObjectContext];
    self.observing = YES;
}

- (void)willTurnIntoFault
{
    [[NSNotificationCenter defaultCenter] removeObserver:self name:NSManagedObjectContextObjectsDidChangeNotification object:self.managedObjectContext];

    self.observing = NO;
    [super willTurnIntoFault];
}

- (void)myManagedObjectContextDidChange:(NSNotification*)notification {
    NSDictionary *userInfo = [notification userInfo];
    NSMutableSet *changedObjects = [NSMutableSet new];
    NSSet *objects = nil;

    objects = [userInfo objectForKey:NSInsertedObjectsKey];
    [changedObjects unionSet:objects];

    objects = [userInfo objectForKey:NSUpdatedObjectsKey];
    [changedObjects unionSet:objects];

    objects = [userInfo objectForKey:NSDeletedObjectsKey];
    [changedObjects unionSet:objects];

    NSPredicate *predicate = [NSPredicate predicateWithFormat:@"SELF IN %@", self.bars];
    NSSet *updatedObjects = [changedObjects filteredSetUsingPredicate:predicate];

    if (updatedObjects.count > 0) {
        NSDate *now = [NSDate date];

        if (self.modificationDate == nil || [now timeIntervalSinceDate:self.modificationDate] > 1.0) {
            self.modificationDate = now;
        }
    }
}

@end

1 个答案:

答案 0 :(得分:0)

检查何时调用didTurnIntoFault。如果被调用,请尝试:

[[NSNotificationCenter defaultCenter] removeObserver:self]

请注意,contextDidChange通知可能在与didTurnIntoFault不同的线程上调用。所以你可能会遇到竞争条件。确保在同一个线程上完成观察的添加和删除(应该是在其上创建managedOject并因此创建托管对象的线程)。