2

ネット上のどこにも答えが見つからなかったので、助けていただければ幸いです。

私は、NSInvocation などの具体的なサブクラスでは実行できないことを理解している NSOperation タスクの結果を取得できるシステムを作成しようとしています。

私は NSOperation サブクラス ( TheEngine-main ) を持っています。これは慣例により抽象的であり、実行するコードの本体を含めるためにfunction を実装するために拡張する必要があります。

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

どんな助けでも大歓迎です!

4

2 に答える 2

1

バックNSOperationグラウンド スレッドで実行されている可能性があります。そのスレッドがなくなった場合、またはそのスレッドが実行ループをポンピングできなかった場合、への呼び出しは起動しperformSelector:withObject:afterDelay:ません。への呼び出しをコメントアウトしましたperformSelectorOnMainThread:...。これはうまくいきましたか?

おそらく、これをメインスレッドで実行するか、これを実行する必要がありますperformSelector:withObject:( なしでafterDelay:)。performSelector:withObject:実行ループは必要ありません。

于 2011-09-01T23:50:15.650 に答える
0

ロブが示唆したように、コードは呼び出しと同様にバックグラウンド スレッドで実行されていました。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];

}

これにより、正しいデータを使用してTheTasktheSelectorが呼び出されました。参加してくれてありがとう:)

于 2011-09-02T17:01:00.823 に答える