2012-02-23 4 views
2


NSOperationサブクラスですべての非同期ダウンロード(すべてのオペレーションに独自のスレッドがあります)操作をパケット化し、後でNSOperationQueueに追加するダウンロードマネージャークラスを構築しようとしています。ダウンロードマネージャクラス(シングルトン)は、いくつかの要件に合致するキュー上で動作し、操作を取り消すいくつかのメソッドも公開しています。
これは、一般的な操作の種類(アップロード、ダウンロード、解析など)ごとに異なる種類のNSOperationを返す種類のクラスター(抽象ファクトリ)の作成を開始する手順です。
クラスはダウンロード操作ではうまくいくように見えますが、操作の途中で操作をキャンセルするメソッドを呼び出すと、操作は正常にキャンセルされますが、後でアプリケーションがクラッシュすることはほとんどありません。私はすべての操作をキャンセルしない場合、すべて正常に動作します。すべての操作はKVOを使用して観察されます。 操作を削除する方法は以下のようになります。NSOperationQueueからNSOperationをキャンセルするとクラッシュする

- (void) cancelDownloadOperationWithID:(NSString *)aUUID{ 
@synchronized(self){ 
    [self.dowloadQueue setSuspended:YES]; //downloadQueue is an NSOperationQueue 
    NSArray * downloadOperations = [self.dowloadQueue operations]; 
    NSPredicate * aPredicate = [NSPredicate predicateWithFormat:@"SELF.connectionID == %@",aUUID]; //SELF is the signleton instance of the download manager 
    NSArray * filteredArray = [downloadOperations filteredArrayUsingPredicate:aPredicate]; 
    if ([filteredArray count]==0) { 
     [self.dowloadQueue setSuspended:NO]; 
     return; 
    } 
    [filteredArray makeObjectsPerformSelector:@selector(cancel)]; 
    NSLog(@"Cancelled %d operations",[filteredArray count]); 
    [self.dowloadQueue setSuspended:NO]; 
    } 
} 

クラッシュログはかなり不可解ですが、BAD_EXC_ACCESS(おそらくゾンビ)で、私はARCの下だと気づきます。

0x00a90ea8 <+0393> jle 0xa90d9f <____NSOQSchedule_block_invoke_0+128> 
0x00a90eae <+0399> mov -0x38(%ebp),%ecx 
0x00a90eb1 <+0402> mov -0x34(%ebp),%esi 
0x00a90eb4 <+0405> mov (%esi,%ecx,1),%ecx 
0x00a90eb7 <+0408> mov -0x40(%ebp),%esi 
0x00a90eba <+0411> cmpb $0x0,(%ecx,%esi,1) 
0x00a90ebe <+0415> jne 0xa90d9f <____NSOQSchedule_block_invoke_0+128> 
0x00a90ec4 <+0421> mov (%edi,%eax,1),%esi 
0x00a90ec7 <+0424> mov (%esi,%edx,1),%ebx 
0x00a90eca <+0427> mov %ebx,-0x2c(%ebp) 
0x00a90ecd <+0430> mov -0x44(%ebp),%ebx 
0x00a90ed0 <+0433> cmpl $0x50,(%esi,%ebx,1) 
0x00a90ed4 <+0437> mov %edi,%ebx 
0x00a90ed6 <+0439> jne 0xa90e96 <____NSOQSchedule_block_invoke_0+375> 
0x00a90ed8 <+0441> mov -0x48(%ebp),%ebx 
0x00a90edb <+0444> cmpb $0x0,(%esi,%ebx,1) 
0x00a90edf <+0448> mov %edi,%ebx 
0x00a90ee1 <+0450> je  0xa90e96 <____NSOQSchedule_block_invoke_0+375> 

いくつか私にそれについての提案を与えることができますか?
Thanx Andrea

答えて

4

まあ答えはかなりシンプルでした。 NSOperationサブクラスのオーバーライドされた-cancelメソッドでは、完成したVARと実行中のVARの両方を設定して、適切なKVOコールバックをトリガしました。問題は、キューがクラッシュしたKVOコールバックをトリガしたNSOperationQueueで-startメソッドを起動しようとしたときに、キャンセルされても操作がNSOperationQueueにとどまることです。

回避策が実行されていないときにキャンセルされた場合は、メソッドの実装の開始直後に終了varをYESに設定する必要があります。 NOに実行する。

+0

これは私にとって非常に奇妙な行動のように思えるが、なぜキューがまだ開始されていない操作を続けるだろう、/キューに入れられましたか?ありがとう、それは私のクラッシュを修正しました。 –

+0

私にとっても、意味がありますが、私たちはデキューしていません。 – Andrea

3

受け入れられた回答が私に役立ちます。他の人がそれに遭遇した場合にこれをクリアするのを助けるために、非同期操作が実行を開始する前に- cancelisFinishedを不適切に内部に設定することによってこのクラッシュを経験しました。

よりもむしろ操作はすでにisExecutingだった場合、私はここで示唆したように、その後- startに、私はすぐにisFinishedを設定、変更のみisFinishedに私の- cancelを切り替え、ことをやって。ヴォラ、墜落した。

+1

これに対していくつかのコードを投稿できますか...ありがとう – user1028028

1

ここでは、2件の以前の回答を使用して迅速で作品だ:

override func cancel() { 
    super.cancel() 

    if executing { 
     executing = false 
     finished = true 
    } 

    task.cancel() 
} 

override func start() { 
    if cancelled { 
     finished = true 
     return 
    } 

    executing = true 

    main() 
} 

override func main() { 
    task.resume() 
} 
関連する問題