I've noticed that implementing `NSURLSessionDataDelegate` and starting a task will very occasionally will throw an EXC_BAD_ACCESS. The actual calling method that gives the error seems to vary but always comes from `CFNetwork`. For the most part, the calling method comes from `NSURLSession delegate_dataTask:didReceiveData:completionHandler`. I've attached a crash log below. I've also attached my implementation of `NSURLSessionDataDelegate`.
I can semi-reliably recreate this by running the loop below in the Simulator. It also happens on actual devices, but is much more likely on the Simuatlor. Which makes me think that it's a concurrency issue, affected by the number of cores/processing power. It does seem to happen more often with larger files. Have I implemented something wrong here? Is there a good way to debug from this stacktrace?
I've tested on iOS10 and 10.1.1 with the same results. This does not occur on iOS 9.3.
To reproduce, run this in the Simulator for about two minutes (you must also include the Downloader class below):
var i = 0
while true {
print("conn \(i)")
let url = "http://qthttp.apple.com.edgesuite.net/1010qwoeiuryfg/3340/33409.ts"
let c = Downloader(url: url)
c.start()
c.waitForFinish()
i += 1
}
Implementation:
class Downloader: NSObject, NSURLSessionDataDelegate {
private let url: String
var finished = false
let finishCondition = NSCondition()
init(url:String) {
self.url = url
super.init()
}
func start() {
let config = NSURLSessionConfiguration.defaultSessionConfiguration()
let session = NSURLSession(configuration: config,
delegate: self,
delegateQueue: nil)
guard let u = NSURL(string: url) else {
return
}
let request = NSMutableURLRequest(URL: u)
let task = session.dataTaskWithRequest(request)
task.resume()
}
func URLSession(session: NSURLSession, dataTask: NSURLSessionDataTask,
didReceiveData data: NSData) {
}
func URLSession(session: NSURLSession,
task: NSURLSessionTask,
didCompleteWithError error: NSError?) {
session.invalidateAndCancel()
}
func URLSession(session: NSURLSession, dataTask: NSURLSessionDataTask,
didReceiveResponse response: NSURLResponse,
completionHandler: (NSURLSessionResponseDisposition) -> Void) {
completionHandler(NSURLSessionResponseDisposition.Allow)
}
func waitForFinish() {
finishCondition.lock()
while !finished {
finishCondition.wait()
}
finishCondition.unlock()
}
func URLSession(session: NSURLSession, didBecomeInvalidWithError error: NSError?) {
finishCondition.lock()
finished = true
finishCondition.broadcast()
finishCondition.unlock()
}
}
Crash log #1:
* thread #5: tid = 0x25923, 0x0000000100042e8c libBacktraceRecording.dylib`__gcd_queue_item_enqueue_hook_block_invoke, queue = 'com.apple.NSURLSession-work', stop reason = EXC_BAD_ACCESS (code=1, address=0xf8686a68b98c6ec8)
* frame #0: 0x0000000100042e8c libBacktraceRecording.dylib`__gcd_queue_item_enqueue_hook_block_invoke
frame #1: 0x000000010004241c libBacktraceRecording.dylib`gcd_queue_item_enqueue_hook + 232
frame #2: 0x000000010065dee8 libdispatch.dylib`_dispatch_introspection_queue_item_enqueue_hook + 40
frame #3: 0x000000010063cba4 libdispatch.dylib`_dispatch_queue_push + 196
frame #4: 0x000000018ba50500 Foundation`iop_promote_qos_outward + 112
frame #5: 0x000000018ba4e524 Foundation`-[NSOperation setQualityOfService:] + 168
frame #6: 0x000000018b9d7714 Foundation`-[NSOperationQueue addOperationWithBlock:] + 76
frame #7: 0x000000018b73f82c CFNetwork`-[NSURLSession delegate_dataTask:didReceiveData:completionHandler:] + 208
frame #8: 0x000000018b5a2c5c CFNetwork`-[__NSCFLocalSessionTask _task_onqueue_didReceiveDispatchData:completionHandler:] + 276
frame #9: 0x000000018b5a5474 CFNetwork`-[__NSCFLocalSessionTask connection:didReceiveData:completion:] + 164
frame #10: 0x000000018b647bf0 CFNetwork`__48-[__NSCFURLLocalSessionConnection _tick_running]_block_invoke + 120
frame #11: 0x000000018b647b60 CFNetwork`-[__NSCFURLLocalSessionConnection _tick_running] + 344
frame #12: 0x000000018b648c74 CFNetwork`-[__NSCFURLLocalSessionConnection _didReceiveData:] + 412
frame #13: 0x000000018b64af8c CFNetwork`SessionConnectionLoadable::_loaderClientEvent_DidReceiveData(__CFArray const*) + 52
frame #14: 0x000000018b6f823c CFNetwork`___ZN19URLConnectionLoader19protocolDidLoadDataEPK8__CFDatax_block_invoke_2 + 44
frame #15: 0x000000018b64b58c CFNetwork`___ZN25SessionConnectionLoadable21withLoaderClientAsyncEU13block_pointerFvP21LoaderClientInterfaceE_block_invoke + 32
frame #16: 0x000000010063125c libdispatch.dylib`_dispatch_call_block_and_release + 24
frame #17: 0x000000010063121c libdispatch.dylib`_dispatch_client_callout + 16
frame #18: 0x000000010063eb54 libdispatch.dylib`_dispatch_queue_serial_drain + 1136
frame #19: 0x0000000100634ce4 libdispatch.dylib`_dispatch_queue_invoke + 672
frame #20: 0x0000000100640e6c libdispatch.dylib`_dispatch_root_queue_drain + 584
frame #21: 0x0000000100640bb8 libdispatch.dylib`_dispatch_worker_thread3 + 140
frame #22: 0x000000018a01e2b8 libsystem_pthread.dylib`_pthread_wqthread + 1288
frame #23: 0x000000018a01dda4 libsystem_pthread.dylib`start_wqthread + 4