2010-10-22 27 views
6

Tôi đang gặp khó khăn khi cố gắng hủy yêu cầu trong NSOperationQueue.Đâm với ASIHTTPRequest và NSOperationQueue khi hủy hoạt động

Trước khi deallocating đối tượng 'engine' của tôi, tôi gọi phương thức cancelOperations để hủy mọi thứ trong hàng đợi, vì vậy điều này sẽ bao gồm trong ASIHTTPRequests chuyến bay và hàng đợi ... ví dụ:

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

Bây giờ, Trong động cơ của tôi, tôi có một số phương pháp loại getContent, vì vậy hàng đợi của tôi có đối tượng yêu cầu khác nhau trong đó. Dòng chảy khi sử dụng một đối tượng Engine là:

1) Mở View Controller - xem đã tải - alloc và init đối tượng
2 Engine) // Gọi phương pháp phong cách getContent khác nhau để xếp hàng lên một số hoạt động
3) Khi xem thoát, gọi [engine cancelOperations]; để (a) Dừng bất kỳ yêu cầu mạng nào trong chuyến bay và cũng để trống hàng đợi
4) Phân bổ chế độ xem và với động cơ đó: [phát hành động cơ];

Điều này hoạt động tốt nếu tất cả yêu cầu đã hoàn thành trong hàng đợi (vì nó trống), tuy nhiên nếu tôi hủy kích hoạt trong khi yêu cầu đang hoạt động, ứng dụng sẽ gặp lỗi EXC_BAD_ACCESS ... nhưng SAU KHI động cơ được deallocated thành công .. .

Mọi ý tưởng tại sao điều này sẽ là?

--EDIT-- Thêm backtrace cho lỗi:

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 

Trả lời

4

Bạn không nhả hàng đợi hoạt động của bạn trong dealloc ...

Một nghi can là mô hình đoàn:

[request setDelegate:self];

Nếu đối tượng self bị hủy và yêu cầu không phải là, khi yêu cầu 'hoàn thành', nó sẽ cố gắng thông báo cho một số rác trong bộ nhớ, do đó bị lỗi.

UPDATE: để vá lỗi này, thêm mã này trước khi hủy:

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

Tôi có cần giải phóng nó nếu được đặt để tự động phát hành không? Tôi biết chắc chắn rằng tôi đang phá hủy động cơ sau khi tôi gọi [engine cancelOperations] - vì vậy điều đó vẫn có thể là một vấn đề? – mootymoots

+0

Bạn làm '[self setQueue: ...]'. Tôi giả sử bạn có một tài sản hàng đợi được giữ lại. Nếu không, đó là một mối nguy hiểm lớn, vì hàng đợi của bạn có thể được giải phóng bất cứ lúc nào. – jv42

+0

xin lỗi, vâng, bạn đúng ... những gì về tự hủy của tôi? Tôi nghĩ rằng waitUntilAllOperationsAreFinished sẽ ngừng ứng dụng của tôi tiếp tục cho đến khi hàng đợi trống? – mootymoots

0

Hãy chắc chắn rằng bạn đang chạy một phiên bản gần đây của git ASIHTTPRequest - v1.7 chứa một vài điều kiện chủng tộc đó sẽ gây ra tai nạn khi hủy yêu cầu.

+0

Tôi có phiên bản mới nhất mà tôi sợ ... – mootymoots

+0

Ồ, đáng được kiểm tra. Bạn có thể thêm một backtrace cho vụ tai nạn cho câu hỏi của bạn để chúng tôi có thể xem chính xác khu vực mã nào vẫn đang chạy? – JosephH

+0

Xin chào - đã thêm ở trên – mootymoots

4

Tôi nghĩ jv42 là chính xác về nguyên nhân. Tuy nhiên, có một người trợ giúp hữu ích để làm sạch các đại biểu ...

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

Có ai tìm thấy phương pháp nhanh hơn cho điều này ... có thể không liên quan đến yêu cầu?

0

Tôi đã gặp tình huống tương tự khi chạy ASINetworkQueue với nhiều yêu cầu.

Tôi đã xóa bản phát hành dealloc cho hàng đợi và tự động phát hành. Sau đó tôi áp dụng gợi ý tuyệt vời của Leah để lặp lại cho các đại biểu. Sau đó, tôi đặt bản phát hành của hàng đợi trong queueRequestFinished delegate và nó đã giải quyết vấn đề của tôi!

bulkQueue = [[ASINetworkQueue alloc] init]; 

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

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

} 

Hy vọng điều này sẽ giúp ai đó ra ngoài! :-)

+0

Ồ, ví dụ này làm việc cho phiên bản 1.8.1 và tôi cũng đã thử nghiệm để đảm bảo rằng nó không phải là một rò rỉ bộ nhớ tiềm ẩn trong trường hợp của tôi. – August

Các vấn đề liên quan