1

I have troubles with multiple threads. Here is the situation:

I make asynchronous requests to backend and, in some cases, need to cancel these. Canceling the requests happens in a separate thread. All requests to the backend are canceled and, as I exit a screen, multiple class instances are deallocated.

When I have the order request-cancel, everything works fine. However, sometimes the cancel method is invoked when I am already in the middle of the finish method (which needs a little bit time because of decoding and conversion of data). In such cases, the app crashes, a messages to deallocated instance is sent. It is not an exception that can be easily cached, I get the crash even when I check for the existence of the instances a line before. Actually, if I understand it right, the instance of the class where the finish and the cancel method are located, is deallocated. Nevermind, the problem is that the thread is switched in the middle of the finish method and I need to prevent that.

My question is: Is there a way to block switching the thread in the middle of a method? To declare this method as a whole (transaction)? Or is there another standard solution for such a problem?

I read this post but I don't really understand whether it can be used in my case or how to do that.

EDIT: Canceling

for (XXX *request in [XXX sharedQueue].operations)
{
    [request setDelegate:nil];
    [request setDownloadProgressDelegate:nil];
    [request setUploadProgressDelegate:nil];
    [request setQueue:nil];
    [request cancel];
}

XXX is the class used for the requests.

Order of the methods

Here is the order in which the methods are invoked (in the cases of error). Handler is the class for handling the requests.

Handler 1: make request
Handler 1: finish begin
Handler 2: cancel begin
Handler 2: cancel end
Handler 2: dealloc
Handler 1: dealloc
Handler 1: finish middle

Handler 1 and 2 are two instances of the class. The first one is deallocated in the middle of the finish method, so at the end of this I get a crash. Deallocating it is normal because after cancel I go to another view and basically everything gets deallocated.

My ideas for solution are either to somehow prevent going back to the finish method or to execute the entire finish method before switching the thread. Unfortunately, I have no idea how one of these could be implemented.

4

3 に答える 3

2

次のアプローチが役立つ場合があります。

  1. すべてのリクエストを管理するコントローラーにフラグを追加します。

  2. リクエスト終了ブロックが入力されたら、次のようにします。

    completionBlock:^() {
       @synchronized(self.myFinishFlag) {
           ...
       }
    }
    
  3. cancel メソッドで次のようにします。

    -(void)userCancelledRequests:(id)sender {
    
       @synchronized(self.myFinishFlag) {
           ...
       }
    }
    

これにより、'userCancelledRequests body if a finish block is currently running (i.e., lockingself.myFinishFlag`) の実行が遅延します。

お役に立てれば。

于 2013-10-16T10:37:19.093 に答える
0

ブロックする最善の方法は、すべての操作を専用キューで実行することです。キャンセルしたいときは、次のようにします。

dispatch_async(_someQueue, ^{
    for (XXX *request in [XXX sharedQueue].operations)
    {
        [request setDelegate:nil];
        [request setDownloadProgressDelegate:nil];
        [request setUploadProgressDelegate:nil];
        [request setQueue:nil];
        [request cancel];
    }
});

その後、終了したコールバックがトリガーされると、次のことができます。

dispatch_async(_someQueue, ^{
    if ([request isCancelled] == NO)
    {
        // Process request
    }
});

_someQueue が同時キューとしてマークされていない限り、これでうまくいくはずです。

于 2013-10-16T10:41:08.393 に答える