How to workaround URLSession issue in watchOS 6.1.1

Issue #577

https://stackoverflow.com/questions/59724731/class-avassetdownloadtask-is-implemented-in-both-cfnetwork-and-avfoundation

1
2
3
objc[45250]: Class AVAssetDownloadTask is implemented in both /Applications/Xcode.app/Contents/Developer/Platforms/WatchOS.platform/Library/Developer/CoreSimulator/Profiles/Runtimes/watchOS.simruntime/Contents/Resources/RuntimeRoot/System/Library/Frameworks/CFNetwork.framework/CFNetwork (0x4ddd0ec) and /Applications/Xcode.app/Contents/Developer/Platforms/WatchOS.platform/Library/Developer/CoreSimulator/Profiles/Runtimes/watchOS.simruntime/Contents/Resources/RuntimeRoot/System/Library/Frameworks/AVFoundation.framework/AVFoundation (0x16aea494). One of the two will be used. Which one is undefined.

objc[45250]: Class AVAssetDownloadURLSession is implemented in both /Applications/Xcode.app/Contents/Developer/Platforms/WatchOS.platform/Library/Developer/CoreSimulator/Profiles/Runtimes/watchOS.simruntime/Contents/Resources/RuntimeRoot/System/Library/Frameworks/CFNetwork.framework/CFNetwork (0x4dddd44) and /Applications/Xcode.app/Contents/Developer/Platforms/WatchOS.platform/Library/Developer/CoreSimulator/Profiles/Runtimes/watchOS.simruntime/Contents/Resources/RuntimeRoot/System/Library/Frameworks/AVFoundation.framework/AVFoundation (0x16aea4bc). One of the two will be used. Which one is undefined.

Then URLSession stops working.

1
2020-01-13 22:50:12.430920+0100 MyAppWatch WatchKit Extension[45250:2099229] Task <3CECDE81-59B9-4EDE-A4ED-1BA173646037>.<1> finished with error [-999] Error Domain=NSURLErrorDomain Code=-999 "cancelled" UserInfo={NSErrorFailingURLKey=https://myapp.com/def.json, NSErrorFailingURLStringKey=https://myapp.com/def.json, NSLocalizedDescription=cancelled}

The workaround is to remove Combine based API, and use completion block.

Instead of dataTaskPublisher which hangs indefinitely, no sink is reported

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
URLSession.shared
.dataTaskPublisher(for: url)
.map({ $0.data })
.decode(type: T.self, decoder: JSONDecoder())
.eraseToAnyPublisher()
.receive(on: RunLoop.main)
.sink(receiveCompletion: { completionStatus in
switch completionStatus {
case .finished:
break
case .failure(let error):
completion(.failure(error))
}
}, receiveValue: { value in
completion(.success(value))
})

just use normal

1
2
3
4
5
6
7
8
9
let task = URLSession.shared.dataTask(with: url, completionHandler: { data, response, error in
if let data = data, let model = try? JSONDecoder().decode(T.self, from: data) {
completion(.success(model))
} else {
completion(.failure(error ?? ServiceError.noInternet))
}
})

task.resume()

Comments