PerformSelector в подклассе NSOperation

Я не мог найти ответ нигде в сети, поэтому любая помощь будет оценена.

Я пытаюсь создать систему, с помощью которой я могу получать результаты задачи NSOperation, которую, как я понимаю, нельзя выполнить с помощью конкретных подклассов, таких как NSInvocation.

У меня есть подкласс NSOperation (TheEngine), который является абстрактным по соглашению и должен быть расширен для реализации функции -main, чтобы включить тело кода для выполнения.

TheEngine содержит следующую функцию инициализации, задача которой состоит в том, чтобы просто отметить theSelector и theObject, которым принадлежит селектор. Он также регистрирует наблюдателя KV для свойства isFinished:

-(id)initWithCallbackSelector:(SEL)theSelector inObject:(id)theObject

В моей функции observeValueForKeyPath:ofObject:change:context: я хотел бы вызвать функцию обратного вызова следующим образом:

NSLog(@"Some debug text to ensure this function is being called", nil);
[theObject performSelector:theSelector withObject:someData afterDelay:0];

Весь процесс происходит так:

aViewController запускает расширение TheEngine — скажем, TheTask, вызывая следующее и добавляя его в очередь операций.

TheTask* TT = [[TheTask alloc] initWithCallbackSelector:
    @selector(resultHandler:) inObject:theObject];

Кажется, все работает, как и ожидалось, без каких-либо ошибок или исключений. Но когда выполнение достигает observeValueForKeyPath:ofObject:change:context:, обратный вызов фактически не вызывается. Я новичок в Obj-C, поэтому я не совсем уверен, правильно ли я понимаю этот тип потоковой передачи.

Вот весь код:

-(id)initWithCallbackSelector:(SEL)theSelector inObject:(id)theObject{

    if([self init]){

        self.selectorsParentObject      =   theObject;
        self.selectorToCallWhenFinished =   theSelector;


        [self addObserver:self forKeyPath:@"isFinished" options:NSKeyValueObservingOptionNew context:NULL];

        return self;
    }

    return nil; 
}


-(void)observeValueForKeyPath:(NSString*)keyPath ofObject:(id)theObject change:(NSDictionary*)theChange context:(void*)theContext{

    if([keyPath isEqualToString:@"isFinished"]){

        NSLog(@"activity is finished with change: %@", theChange);

        NSLog(@"target object: %@", self.selectorsParentObject);
        NSLog(@"target selector: %@", NSStringFromSelector(self.selectorToCallWhenFinished));

        //[self performSelectorOnMainThread:self.selectorToCallWhenFinished withObject:self.resultData waitUntilDone:NO];
        [self.selectorsParentObject performSelector:@selector(selectorToCallWhenFinished) withObject:self.resultData afterDelay:0];
    }
}

Любая помощь приветствуется!




Ответы (2)


Ваш NSOperation, скорее всего, работает в фоновом потоке. Если этот поток исчезнет или если этому потоку не удастся прокачать свой цикл выполнения, ваш вызов performSelector:withObject:afterDelay: не сработает. Вы закомментировали вызов performSelectorOnMainThread:.... Это сработало?

Вы, вероятно, должны запустить это в основном потоке или запустить это с performSelector:withObject: (без afterDelay:). performSelector:withObject: не требует цикла выполнения.

person Rob Napier    schedule 01.09.2011
comment
спасибо за подсказку, ваша догадка оказалась верной - я выложу внесенные изменения :) - person aktar; 02.09.2011

Как предположил Роб, код выполнялся в фоновом потоке, как и вызов observeValueForKeyPath:ofObject:change:context:

Сначала я изменил код, чтобы селектор запускался в основном потоке с помощью [self performSelectorOnMainThread:@selector(runCallback) withObject:nil waitUntilDone:NO];.

Но в этом случае основным потоком оказывается TheTask, и возникает исключение, поскольку TheTask не владеет theSelector. Чтобы исправить это, я создал дополнительную функцию -runCallback и запустил ее из

-(void)observeValueForKeyPath:(NSString*)keyPath ofObject:(id)theObject change:(NSDictionary*)theChange context:(void*)theContext{

    if([keyPath isEqualToString:@"isFinished"]){

        NSLog(@"activity is finished with change: %@", theChange);

        NSLog(@"target object: %@", self.selectorsParentObject);
        NSLog(@"target selector: %@", NSStringFromSelector(self.selectorToCallWhenFinished));



        [self performSelectorOnMainThread:@selector(runCallback) withObject:nil waitUntilDone:NO];

        //[self performSelectorOnMainThread:self.selectorToCallWhenFinished withObject:self.resultData waitUntilDone:NO];
        //[self.selectorsParentObject performSelector:@selector(selectorToCallWhenFinished) withObject:self.resultData afterDelay:0];
    }
}

и в -runCallback:

-(void)runCallback{

    [self.selectorsParentObject performSelector:self.selectorToCallWhenFinished withObject:self.resultData afterDelay:0];

}

Это вызвало theSelector в TheTask с правильными данными. Спасибо за участие :)

person aktar    schedule 02.09.2011