2010-10-22 14 views
6

Durante il tentativo di annullamento delle richieste in NSOperationQueue sto attraversando un periodo molto difficile.Arresto anomalo con ASIHTTPRequest e NSOperationQueue durante l'annullamento delle operazioni

Prima di deallocare il mio oggetto 'motore', chiamo un metodo cancelOperations per cancellare tutto in coda, quindi questo includerà in volo ASIHTTPRequisiti e quelli in coda ... ad es.

Engine.m

-(void)getContent { 
    if (![self queue]) { 
     [self setQueue:[[[NSOperationQueue alloc] init] autorelease]]; 
    } 

    NSURL *url = [NSURL URLWithString:@"http://allseeing-i.com"]; 
    ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url]; 
    [request setDelegate:self]; 
    [request setDidFinishSelector:@selector(requestDone:)]; 
    [[self queue] addOperation:request]; //queue is an NSOperationQueue 
} 

-(void)requestDone:(ASIHTTPRequest)*request { 

    // Do something with request 
} 

-(void)cancelOperations { 
    [self.queue cancelAllOperations]; 
    [self.queue waitUntilAllOperationsAreFinished]; 
} 

-(void)dealloc { 
    [super dealloc]; 
} 

Ora, nel mio motore ho un certo numero di metodi di tipo getContent, quindi la mia coda ha diversi oggetti richiesta in essa. Il flusso di quando si utilizza un oggetto motore è:

1) Aprire View Controller - Vista ha carico - alloc e init motore oggetto
2) // Chiamata vari metodi stile getContent in fila alcune operazioni
3) Su vista esci, chiama [engine cancelOperations]; al fine di (a) interrompere qualsiasi richiesta di rete in volo e anche svuotare la coda
4) Deallocare la vista e con quella il motore: [rilascio del motore];

Questo funziona bene se tutte le richieste hanno terminato in coda (come è vuoto), se I cancelOperations mentre una richiesta è attiva, l'applicazione si blocca con un errore di EXC_BAD_ACCESS ... ma dopo che il motore è deallocata successo ..

Qualche idea del motivo?

--EDIT-- Aggiunta Backtrace per l'errore:

Exception Type: EXC_BAD_ACCESS (SIGBUS) 
Exception Codes: KERN_PROTECTION_FAILURE at 0x00000000b0000000 
Crashed Thread: 0 Dispatch queue: com.apple.main-thread 

Application Specific Information: 
objc_msgSend() selector name: respondsToSelector: 
iPhone Simulator 225, iPhone OS 4.1 (iPhone 4/8B117) 

Thread 0 Crashed: Dispatch queue: com.apple.main-thread 
0 libobjc.A.dylib     0x02cb5907 objc_msgSend + 27 
1 CoreFoundation     0x02ac95cd __invoking___ + 29 
2 CoreFoundation     0x02ac94a1 -[NSInvocation invoke] + 145 
3 Foundation      0x0015a3ca __NSThreadPerformPerform + 251 
4 CoreFoundation     0x02b39faf __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 15 
5 CoreFoundation     0x02a9839b __CFRunLoopDoSources0 + 571 
6 CoreFoundation     0x02a97896 __CFRunLoopRun + 470 
7 CoreFoundation     0x02a97350 CFRunLoopRunSpecific + 208 
8 CoreFoundation     0x02a97271 CFRunLoopRunInMode + 97 
9 GraphicsServices    0x0320c00c GSEventRunModal + 217 
10 GraphicsServices    0x0320c0d1 GSEventRun + 115 
11 UIKit       0x003e9af2 UIApplicationMain + 1160 
12 Clicky       0x000027d4 main + 102 (main.m:14) 
13 Clicky       0x00002765 start + 53 

Thread 1: Dispatch queue: com.apple.libdispatch-manager 
0 libSystem.B.dylib    0x97cfe942 kevent + 10 
1 libSystem.B.dylib    0x97cff05c _dispatch_mgr_invoke + 215 
2 libSystem.B.dylib    0x97cfe519 _dispatch_queue_invoke + 163 
3 libSystem.B.dylib    0x97cfe2be _dispatch_worker_thread2 + 240 
4 libSystem.B.dylib    0x97cfdd41 _pthread_wqthread + 390 
5 libSystem.B.dylib    0x97cfdb86 start_wqthread + 30 

Thread 2: 
0 libSystem.B.dylib    0x97cfd9d2 __workq_kernreturn + 10 
1 libSystem.B.dylib    0x97cfdf68 _pthread_wqthread + 941 
2 libSystem.B.dylib    0x97cfdb86 start_wqthread + 30 

Thread 3: WebThread 
0 libSystem.B.dylib    0x97cd80fa mach_msg_trap + 10 
1 libSystem.B.dylib    0x97cd8867 mach_msg + 68 
2 CoreFoundation     0x02b3a436 __CFRunLoopServiceMachPort + 150 
3 CoreFoundation     0x02a97984 __CFRunLoopRun + 708 
4 CoreFoundation     0x02a97350 CFRunLoopRunSpecific + 208 
5 CoreFoundation     0x02a97271 CFRunLoopRunInMode + 97 
6 WebCore       0x034093a3 RunWebThread(void*) + 483 
7 libSystem.B.dylib    0x97d0581d _pthread_start + 345 
8 libSystem.B.dylib    0x97d056a2 thread_start + 34 

Thread 4: 
0 libSystem.B.dylib    0x97cfd9d2 __workq_kernreturn + 10 
1 libSystem.B.dylib    0x97cfdf68 _pthread_wqthread + 941 
2 libSystem.B.dylib    0x97cfdb86 start_wqthread + 30 

Thread 5: 
0 libSystem.B.dylib    0x97cd80fa mach_msg_trap + 10 
1 libSystem.B.dylib    0x97cd8867 mach_msg + 68 
2 CoreFoundation     0x02b3a436 __CFRunLoopServiceMachPort + 150 
3 CoreFoundation     0x02a97984 __CFRunLoopRun + 708 
4 CoreFoundation     0x02a97350 CFRunLoopRunSpecific + 208 
5 CoreFoundation     0x02a9a614 CFRunLoopRun + 84 
6 Clicky       0x0001fdb7 +[ASIHTTPRequest runRequests] + 167 (ASIHTTPRequest.m:4093) 
7 Foundation      0x0014576c -[NSThread main] + 81 
8 Foundation      0x001456f8 __NSThread__main__ + 1387 
9 libSystem.B.dylib    0x97d0581d _pthread_start + 345 
10 libSystem.B.dylib    0x97d056a2 thread_start + 34 

Thread 6: 
0 libSystem.B.dylib    0x97cd80fa mach_msg_trap + 10 
1 libSystem.B.dylib    0x97cd8867 mach_msg + 68 
2 CoreFoundation     0x02b3a436 __CFRunLoopServiceMachPort + 150 
3 CoreFoundation     0x02a97984 __CFRunLoopRun + 708 
4 CoreFoundation     0x02a97350 CFRunLoopRunSpecific + 208 
5 CoreFoundation     0x02a97271 CFRunLoopRunInMode + 97 
6 Foundation      0x0017ab86 +[NSURLConnection(NSURLConnectionReallyInternal) _resourceLoadLoop:] + 398 
7 Foundation      0x0014576c -[NSThread main] + 81 
8 Foundation      0x001456f8 __NSThread__main__ + 1387 
9 libSystem.B.dylib    0x97d0581d _pthread_start + 345 
10 libSystem.B.dylib    0x97d056a2 thread_start + 34 

Thread 7: 
0 libSystem.B.dylib    0x97cf7086 select$DARWIN_EXTSN + 10 
1 CoreFoundation     0x02acbb5e __CFSocketManager + 798 
2 libSystem.B.dylib    0x97d0581d _pthread_start + 345 
3 libSystem.B.dylib    0x97d056a2 thread_start + 34 

Thread 8: 
0 libSystem.B.dylib    0x97cfd9d2 __workq_kernreturn + 10 
1 libSystem.B.dylib    0x97cfdf68 _pthread_wqthread + 941 
2 libSystem.B.dylib    0x97cfdb86 start_wqthread + 30 

Thread 0 crashed with X86 Thread State (32-bit): 
    eax: 0x06641500 ebx: 0x000143f3 ecx: 0x0008e1c8 edx: 0x06606075 
    edi: 0xb0000000 esi: 0x066554c4 ebp: 0xbfffdef8 esp: 0xbfffdec4 
    ss: 0x0000001f efl: 0x00010206 eip: 0x02cb5907 cs: 0x00000017 
    ds: 0x0000001f es: 0x0000001f fs: 0x00000000 gs: 0x00000037 
    cr2: 0xb0000000 

risposta

4

non si rilascia la coda di operazioni in dealloc ...

un sospetto è il modello della delegazione:

[request setDelegate:self];

Se l'oggetto self viene distrutto e la richiesta non è, quando la richiesta 'completa', verrà prova a notificare alcuni rifiuti in memoria, quindi crash.

UPDATE: per rattoppare questo, aggiungere questo codice prima di annullare:

for (ASIHTTPRequest *request in queue.operations) 
{ 
    [request setDelegate: nil]; 
    [request setDidFinishSelector: nil]; 
} 
+0

Devo rilasciarlo se è impostato su autorelease? So per certo che sto distruggendo il motore dopo aver chiamato [engine cancelOperations] - quindi potrebbe ancora essere un problema valido? – mootymoots

+0

Si esegue '[self setQueue: ...]'. Suppongo che tu abbia una proprietà di coda che è mantenuta. Se non lo è, è un grosso pericolo, dal momento che la tua coda può essere rilasciata in qualsiasi momento. – jv42

+0

scusate, sì avete ragione ... e la mia auto distrugge? Pensavo che waitUntilAllOperationsAreFinished avrebbe impedito alla mia app di continuare finché la coda non fosse vuota? – mootymoots

0

Assicurarsi che si sta eseguendo una versione recente di git ASIHTTPRequest - v1.7 contiene un paio di condizioni di gara che sarà provoca crash quando si annulla richieste.

+0

Ho l'ultima versione che ho paura ... – mootymoots

+0

Oh beh, valeva la pena controllare. Puoi aggiungere un backtrace per il crash alla tua domanda in modo da poter vedere esattamente quale area di codice è ancora in esecuzione? – JosephH

+0

Ciao - ho aggiunto sopra – mootymoots

4

Penso che jv42 sia corretto sulla causa. Tuttavia, c'è un aiuto a portata di mano per ripulire delegati ...

-(void)dealloc { 
    for (ASIHTTPRequest *request in queue.operations) { 
    [request clearDelegatesAndCancel]; 
    } 
    [queue release]; 
    [super dealloc]; 
} 

Qualcuno ha trovato un metodo più veloce per questo ... forse uno che non coinvolge il ciclo sopra le richieste?

0

Avevo la stessa situazione durante l'esecuzione di un ASINetworkQueue con più richieste.

Ho rimosso il rilascio dealloc per la coda e l'autorelease. Ho quindi applicato l'eccellente suggerimento di Leah di passare attraverso a zero i delegati. Quindi ho messo la versione della coda nel delegato queueRequestFinished e ha risolto il mio problema!

bulkQueue = [[ASINetworkQueue alloc] init]; 

[bulkQueue setQueueDidFinishSelector:@selector(queueRequestFinished:)]; 

-(void)queueRequestFinished:(ASINetworkQueue *)queue 
{ 
    for (ASIHTTPRequest *request in queue.operations) 
    { 
     [request setDelegate: nil]; 
     [request setDidFinishSelector: nil]; 
    } 

} 

Spero che questo aiuti qualcuno fuori! :-)

+0

Oh, questo esempio ha funzionato per la versione 1.8.1 e ho anche provato a verificare che non si trattasse di una potenziale perdita di memoria nel mio caso. – August

Problemi correlati