任务AFNetworking死锁(tasksForKeyPath) [英] AFNetworking deadlock on tasks (tasksForKeyPath)

查看:726
本文介绍了任务AFNetworking死锁(tasksForKeyPath)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我相信这是一个愚蠢的,我在做,但一个小时后,我看不到它。也许你可以。 编辑:这是在设备(iPhone 5S w / iOS 8.4)上,而不是模拟器。

I'm sure this is something stupid that i'm doing, but after an hour I cannot see it. Maybe you can. Edit: this is on a device (iPhone 5S w/iOS 8.4), not the simulator.

DownloadManager,一个单例,它使用BackgroundSession子类化AFHTTPSessionManager。它以前工作正常,但现在我做了一些事情,结果是AFNetworking死锁在 setDownloadTaskDidFinishDownloadingBlock ,当我引用 self.tasks.count

I have an iOS 8 app with a DownloadManager, a singleton that subclasses AFHTTPSessionManager using a BackgroundSession. It used to work fine, but now I've done something and the result is that AFNetworking deadlocks in setDownloadTaskDidFinishDownloadingBlock, when I reference self.tasks.count:

[self setDownloadTaskDidFinishDownloadingBlock:^NSURL *(NSURLSession *session, NSURLSessionDownloadTask *downloadTask, NSURL *location) {
    // POINT OF THIS BLOCK: RETURNS A FILENAME URL WHERE THE DOWNLOAD SHOULD GET STORED
    __strong typeof(self) strongSelf = weakS;
    if( !strongSelf )
        return nil;

    // deadlocks here on tasks.count
    DDLogVerbose(@"setDownloadTaskDidFinishDownloadingBlock, start; dataTasks - %lu, downloadTasks - %lu", (unsigned long)strongSelf.dataTaskManager.tasks.count, (unsigned long)strongSelf.tasks.count);

dataTaskManager是指一个单独的子类AFHTTPSessionManager,它是一个标准会话上面的日志行不能解决问题。

dataTaskManager refers to a separately subclassed AFHTTPSessionManager which is a standard session (not background) -- removing this from the logging line above does not solve the problem.

DownloadManager的completionQueue在init中设置为与DownloadManager用于一切的相同的序列队列:

DownloadManager's completionQueue is set in init to be the same serial queue that the DownloadManager uses for everything:

    _processingQueue = dispatch_queue_create([[BUNDLE_IDENTIFIER stringByAppendingString:@".BackgroundSessionManager"] cStringUsingEncoding:NSUTF8StringEncoding], NULL);
    dispatch_queue_set_specific(_processingQueue, (__bridge const void *)(_processingQueue), (__bridge void *)(_processingQueue), NULL);
    self.completionQueue = _processingQueue; // set AFNetworking completionQueue to be our queue

...但这似乎没有帮助。

... but that doesn't seem to help.

这是死锁:

(lldb) bt all
  thread #1: tid = 0x137b14, 0x0000000198958e0c libsystem_kernel.dylib`mach_msg_trap + 8, queue = 'com.apple.main-thread', stop reason = signal SIGSTOP
    frame #0: 0x0000000198958e0c libsystem_kernel.dylib`mach_msg_trap + 8
    frame #1: 0x0000000198958c88 libsystem_kernel.dylib`mach_msg + 72
    frame #2: 0x00000001864eb724 CoreFoundation`__CFRunLoopServiceMachPort + 200
    frame #3: 0x00000001864e9678 CoreFoundation`__CFRunLoopRun + 940
    frame #4: 0x00000001864152d4 CoreFoundation`CFRunLoopRunSpecific + 396
    frame #5: 0x000000018fe736fc GraphicsServices`GSEventRunModal + 168
    frame #6: 0x000000018b012f40 UIKit`UIApplicationMain + 1488
    frame #7: 0x00000001000a60a4 Grab`main(argc=1, argv=0x000000016fd8ba80) + 124 at main.m:14
    frame #8: 0x000000019885aa08 libdyld.dylib`start + 4

  thread #2: tid = 0x137b6b, 0x0000000198958c24 libsystem_kernel.dylib`kevent64 + 8, queue = 'com.apple.libdispatch-manager'
    frame #0: 0x0000000198958c24 libsystem_kernel.dylib`kevent64 + 8
    frame #1: 0x0000000100496588 libdispatch.dylib`_dispatch_mgr_invoke + 276
    frame #2: 0x000000010048709c libdispatch.dylib`_dispatch_mgr_thread + 52

  thread #3: tid = 0x137b6c, 0x0000000198973c78 libsystem_kernel.dylib`__workq_kernreturn + 8
    frame #0: 0x0000000198973c78 libsystem_kernel.dylib`__workq_kernreturn + 8
    frame #1: 0x0000000198a0d2dc libsystem_pthread.dylib`_pthread_wqthread + 992

  thread #6: tid = 0x137b6f, 0x0000000198973c78 libsystem_kernel.dylib`__workq_kernreturn + 8
    frame #0: 0x0000000198973c78 libsystem_kernel.dylib`__workq_kernreturn + 8
    frame #1: 0x0000000198a0d2dc libsystem_pthread.dylib`_pthread_wqthread + 992

* thread #7: tid = 0x137b97, 0x0000000198958e48 libsystem_kernel.dylib`semaphore_wait_trap + 8, queue = 'NSOperationQueue 0x17022f180 :: NSOperation 0x170449cf0 (QOS: LEGACY)'
    frame #0: 0x0000000198958e48 libsystem_kernel.dylib`semaphore_wait_trap + 8
    frame #1: 0x0000000100494544 libdispatch.dylib`_dispatch_semaphore_wait_slow + 256
  * frame #2: 0x000000010018e8f4 Grab`-[AFURLSessionManager tasksForKeyPath:](self=0x0000000127d1e050, _cmd=0x0000000100203d49, keyPath=0x000000017042fdc0) + 340 at AFURLSessionManager.m:617
    frame #3: 0x000000010018ee88 Grab`-[AFURLSessionManager tasks](self=0x0000000127d1e050, _cmd=0x0000000191f79785) + 76 at AFURLSessionManager.m:623
    frame #4: 0x00000001000a8efc Grab`__36-[DownloadManager loadSessionBlocks]_block_invoke150(.block_descriptor=<unavailable>, session=0x0000000170132700, downloadTask=0x0000000127e408b0, location=0x00000001702bf860) + 328 at DownloadManager.m:149
    frame #5: 0x0000000100193734 Grab`-[AFURLSessionManager URLSession:downloadTask:didFinishDownloadingToURL:](self=0x0000000127d1e050, _cmd=0x000000018d2b4ddd, session=0x0000000170132700, downloadTask=0x0000000127e408b0, location=0x00000001702bf860) + 292 at AFURLSessionManager.m:1082
    frame #6: 0x0000000185f70b70 CFNetwork`__82-[NSURLSession delegate_downloadTask:didFinishDownloadingToURL:completionHandler:]_block_invoke + 40
    frame #7: 0x000000018741b1c4 Foundation`__NSBLOCKOPERATION_IS_CALLING_OUT_TO_A_BLOCK__ + 16
    frame #8: 0x000000018736c604 Foundation`-[NSBlockOperation main] + 96
    frame #9: 0x000000018735c1cc Foundation`-[__NSOperationInternal _start:] + 636
    frame #10: 0x000000018741df28 Foundation`__NSOQSchedule_f + 228
    frame #11: 0x0000000100484f94 libdispatch.dylib`_dispatch_client_callout + 16
    frame #12: 0x000000010048fdb8 libdispatch.dylib`_dispatch_queue_drain + 780
    frame #13: 0x00000001004882c4 libdispatch.dylib`_dispatch_queue_invoke + 132
    frame #14: 0x00000001004925d4 libdispatch.dylib`_dispatch_root_queue_drain + 772
    frame #15: 0x0000000100494248 libdispatch.dylib`_dispatch_worker_thread3 + 132
    frame #16: 0x0000000198a0d22c libsystem_pthread.dylib`_pthread_wqthread + 816

  thread #12: tid = 0x137b9e, 0x0000000198973c78 libsystem_kernel.dylib`__workq_kernreturn + 8
    frame #0: 0x0000000198973c78 libsystem_kernel.dylib`__workq_kernreturn + 8
    frame #1: 0x0000000198a0d2dc libsystem_pthread.dylib`_pthread_wqthread + 992

  thread #10: tid = 0x137bf9, 0x0000000198958e0c libsystem_kernel.dylib`mach_msg_trap + 8, name = 'com.apple.NSURLConnectionLoader'
    frame #0: 0x0000000198958e0c libsystem_kernel.dylib`mach_msg_trap + 8
    frame #1: 0x0000000198958c88 libsystem_kernel.dylib`mach_msg + 72
    frame #2: 0x00000001864eb724 CoreFoundation`__CFRunLoopServiceMachPort + 200
    frame #3: 0x00000001864e9678 CoreFoundation`__CFRunLoopRun + 940
    frame #4: 0x00000001864152d4 CoreFoundation`CFRunLoopRunSpecific + 396
    frame #5: 0x0000000185ef2594 CFNetwork`+[NSURLConnection(Loader) _resourceLoadLoop:] + 440
    frame #6: 0x0000000187435db8 Foundation`__NSThread__main__ + 1072
    frame #7: 0x0000000198a0fdc8 libsystem_pthread.dylib`_pthread_body + 164
    frame #8: 0x0000000198a0fd24 libsystem_pthread.dylib`_pthread_start + 160

  thread #11: tid = 0x137bfa, 0x0000000198973498 libsystem_kernel.dylib`__select + 8, name = 'com.apple.CFSocket.private'
    frame #0: 0x0000000198973498 libsystem_kernel.dylib`__select + 8
    frame #1: 0x00000001864f1128 CoreFoundation`__CFSocketManager + 672
    frame #2: 0x0000000198a0fdc8 libsystem_pthread.dylib`_pthread_body + 164
    frame #3: 0x0000000198a0fd24 libsystem_pthread.dylib`_pthread_start + 160
(lldb) 


推荐答案

....我想出来了。
由于tasksForKeyPath的实现方式,不可能从setTaskDidCompleteBlock这样的块中调用*。任务,因为下面的NSURLSession方法(getTasksWithCompletionHandler)会回调代理队列,这当然是被原始块像setTaskDidCompleteBlock。
这很糟糕,但是它有点像苹果的错,我想,为使方法获取任务异步...

.... I figured it out. Because of the way tasksForKeyPath is implemented, it is not possible to call .*tasks from the blocks like setTaskDidCompleteBlock, because the NSURLSession method underneath (getTasksWithCompletionHandler) will call back on the delegate queue, which is of course blocked by the original block like setTaskDidCompleteBlock. This sucks, but it's kinda Apple's fault I guess, for making the method that gets tasks asynchronous...

因此,解决方法是避免获取当前来自块的任务,如setTaskDidCompleteBlock(或任何他们调用)

So the workaround is to avoid getting the current tasks from blocks like setTaskDidCompleteBlock (or anything that they call)

这篇关于任务AFNetworking死锁(tasksForKeyPath)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆