observValueForKeyPath не се извиква

Разработвам тестово приложение, в което имам NSOperationQueue. Създавам NSInvocationOperation и наблюдавам свойството "isFinished" на тази операция. Странно, наблюдениетоValueForKeyPath се извиква само понякога. Не мога да разбера промените, които трябва да направя, за да го извиквам всеки път. Моля помогнете.

Ето кода, който съм написал:

-(BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    ........//initialization

    queue = [NSOperationQueue new];
    operation=[NSInvocationOperation new];

    operation = [[NSInvocationOperation alloc]initWithTarget:self     selector:@selector(CreateOperationWithContext:) object:context];

    [operation addObserver:self forKeyPath:@"isFinished" options:(NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld) context:NULL];

    [queue addOperation:operation];

    ..... // launch the view controller
}

-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
    if ([keyPath isEqualToString:@"isFinished"]) {
        NSLog(@"came in");
        [operation removeObserver:self forKeyPath:@"isFinished"];
    }
    else
    {
        [super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
    }
}

person user2122350    schedule 12.08.2013    source източник
comment
Как проверявате кога е и кога не се извиква и дали една и съща проверка в CreateOperationWithContext?   -  person Wain    schedule 12.08.2013
comment
Когато не сте виждали известието, 100% сигурни ли сте, че операцията е била успешно създадена, изпълнена и завършена, въпреки че все още не сте виждали isFinished KVN? Например, ако не може да разреши @selector(CreateOperationWithContext:), тогава операцията никога няма да бъде създадена на първо място. Или, ако CreateOperationWithContext: не успее да завърши (безкраен цикъл и т.н.), операцията също няма да завърши. Независимо от това бих препоръчал да зададете completionBlock за вашата операция, вместо да добавяте наблюдател за ключа isFinished. Той е по-чист и по-надежден.   -  person Rob    schedule 12.08.2013
comment
Здравейте Роб и Вейн, Благодаря за отговорите ви. Функцията CreateOperationWithContext: се извиква всеки път и също се изпълнява успешно. Актуализирам базата данни във функцията и мога да виждам актуализацията всеки път. Само наблюдателят не е уведомен.   -  person user2122350    schedule 13.08.2013


Отговори (1)


Следният код работи за мен. Започнах от шаблона за еднократно приложение за iOS. Ето какво имах:

@implementation SOAppDelegate
{
    NSOperationQueue* queue;
    NSOperation* operation;
}

- (void)CreateOperationWithContext: (id)foo
{
    NSLog(@"Op ran");
}

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    queue = [NSOperationQueue new];
    // operation = [NSInvocationOperation new]; // Commented this out because it's redundant with the next line
    operation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(CreateOperationWithContext:) object:[NSObject new]];
    [operation addObserver:self forKeyPath:@"isFinished" options:(NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld) context:NULL];
    [queue addOperation:operation];
    return YES;
}

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
    if ([keyPath isEqualToString:@"isFinished"])
    {
        NSLog(@"came in");
        [operation removeObserver:self forKeyPath:@"isFinished"];
    }
    else
    {
        [super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
    }
}

// ... rest of empty default app delegate methods here...

@end

В конзолата виждам:

2013-08-13 08:04:15.150 TestOpKVO[71373:20b] Op ran
2013-08-13 08:04:21.903 TestOpKVO[71373:20b] came in

Така че нещо във вашето внедряване на -CreateOperationWithContext: създава проблеми. Въпреки това, все още виждам известието за KVO да се извиква, дори ако променя операцията, за да хвърля изключение.

Ако бях на ваше място, щях да започна от този много елементарен работещ пример и след това да продължа стъпка по стъпка, за да го адаптирам към вашия реален код, като проверявам на всяка стъпка, за да се уверя, че известието все още работи.

Няколко съвета: (които вероятно не са свързани с проблема, който виждате, но са добри практики за използване на KVO)

Първо, използвайте KVO контексти с вашите наблюдения. Това е по-безопасно и по-детерминистично. Вижте отговора, който написах тук за подробности.

Второ, не извиквайте -removeObserver:forKeyPath: от вътрешно повикване на -observeValueForKeyPath: (или -addObserver:... също) за същия keyPath, за който се уведомява. Това има потенциала да обърка вътрешните структури на данните на наблюдателя на KVO и може да причини недетерминистични сривове, които могат да ви подлудят. Вижте отговора, който написах тук за подробности.

person ipmcc    schedule 13.08.2013
comment
работи, ще се опитаме да надградим върху това. CreateOperationWithcontext прави актуализация на база данни. Ще се опитам да съкратя функцията и да тествам. Благодаря ти - person user2122350; 13.08.2013