Issue: API Call Delays (5-10 Minutes) on Real Device in tvOS 18 After Call Completes, Works Fine in Debug Mode and Simulator

I am encountering an issue when making an API call using URLSession with DispatchQueue.global(qos: .background).async on a real device running tvOS 18. The code works as expected on tvOS 17 and in the simulator for tvOS 18, but when I remove the debug mode, After the API call it takes few mintues or 5 to 10 min to load the data on the real device.

Code: Here’s the code I am using for the API call:

appconfig.getFeedURLData(feedUrl: feedUrl, timeOut: kRequestTimeOut, apiMethod: ApiMethod.POST.rawValue) { (result) in
    self.EpisodeItems = Utilities.sharedInstance.getEpisodeArray(data: result)
}

func getFeedURLData(feedUrl: String, timeOut: Int, apiMethod: String, completion: @escaping (_ result: Data?) -> ()) {
    guard let validUrl = URL(string: feedUrl) else { return }
    
    var request = URLRequest(url: validUrl, cachePolicy: .useProtocolCachePolicy, timeoutInterval: TimeInterval(timeOut))
    let userPasswordString = "\(KappSecret):\(KappPassword)"
    let userPasswordData = userPasswordString.data(using: .utf8)
    let base64EncodedCredential = userPasswordData!.base64EncodedString(options: .lineLength64Characters)
    let authString = "Basic \(base64EncodedCredential)"
    let headers = [
        "authorization": authString,
        "cache-control": "no-cache",
        "user-agent": "TN-CTV-\(kPlateForm)-\(kAppVersion)"
    ]
    
    request.addValue("application/json", forHTTPHeaderField: "Content-Type")
    request.httpMethod = apiMethod
    request.allHTTPHeaderFields = headers
    
    let response = URLSession.requestSynchronousData(request as URLRequest)
    
    if response.1 != nil {
        do {
            guard let parsedData = try JSONSerialization.jsonObject(with: response.1!, options: .mutableContainers) as? AnyObject else {
                print("Error parsing data")
                completion(nil)
                return
            }
            print(parsedData)
            completion(response.1)
            return
        } catch let error {
            print("Error: \(error.localizedDescription)")
            completion(response.1)
            return
        }
    }
    
    completion(response.1)
}

import Foundation

public extension URLSession {
    public static func requestSynchronousData(_ request: URLRequest) -> (URLResponse?, Data?) {
        var data: Data? = nil
        var responseData: URLResponse? = nil
        let semaphore = DispatchSemaphore(value: 0)
    let task = URLSession.shared.dataTask(with: request) { taskData, response, error in
        data = taskData
        responseData = response
        if data == nil, let error = error {
            print(error)
        }
        semaphore.signal()
    }
 task.resume()
    _ = semaphore.wait(timeout: .distantFuture)
    return (responseData, data)
}
public static func requestSynchronousDataWithURLString(_ requestString: String) -> (URLResponse?, Data?) {
    guard let url = URL(string: requestString.checkValidUrl()) else { return (nil, nil) }
    let request = URLRequest(url: url)
    return URLSession.requestSynchronousData(request)
}
}

Issue Description: Working scenario: The API call works fine on tvOS 17 and in the simulator for tvOS 18. Problem: When running on a real device with tvOS 18, the API call takes time[enter image description here] when debug mode is disabled, but works fine when debug mode is enabled, Data is loading after few minutes.

Error message: Error Domain=WKErrorDomain Code=11 "Timed out while loading attributed string content" UserInfo={NSLocalizedDescription=Timed out while loading attributed string content} NSURLConnection finished with error - code -1001 nw_read_request_report [C4] Receive failed with error "Socket is not connected" Snapshot request 0x30089b3c0 complete with error: <NSError: 0x3009373f0; domain: BSActionErrorDomain; code: 1 ("response-not-possible")> tcp_input [C7.1.1.1:3] flags=[R] seq=817957096, ack=0, win=0 state=CLOSE_WAIT rcv_nxt=817957096, snd_una=275546887

Environment: Xcode version: 16.1 Real device: Model A1625 (32GB) tvOS version: 18.1

Debugging steps I’ve taken: I’ve verified that the issue does not occur in debug mode. I’ve confirmed that the API call works fine on tvOS 17 and in the simulator (tvOS 18). The error suggests a network timeout (-1001) and a socket connection issue ("Socket is not connected").

Questions:

Is this a known issue with tvOS 18 on real devices? Are there any specific settings or configurations in tvOS 18 that could be causing the timeout error in non-debug mode? Could this be related to how URLSession or networking behaves differently in release mode? I would appreciate any help or insights into this issue!

Answered by DTS Engineer in 814661022

You’ve combined a number of anti-patterns:

  • Don’t use Dispatch global concurrent queues. See Avoid Dispatch Global Concurrent Queues for an explanation as to why.

  • Using the .background QoS is tricky, because work on such queues can be delayed for a long time [1].

  • Don’t try to convert asynchronous code to synchronous code using a semaphore, or any other concurrency primitive for that matter.

Given the above, it’s hard to say exactly what’s going wrong. I recommend that you fix all of these issues and then post back if you continue to have problems.

Of these, only the last one is potentially challenging. However, I don’t think that’s a problem in your specific case. You have a getFeedURLData(…) routine that calls your requestSynchronousData(…) method and then processes the result. However, you don’t need to call URLSession synchronously here, because getFeedURLData(…) is already asynchronous, that is, it has a completion handler. So instead of this:

func getFeedURLData(…) {
    …
    let response = URLSession.requestSynchronousData(…)
    … process response …
    completion(response.1)    
}

do this:

func getFeedURLData(…) {
    …
    let response = make an asynchronous request {
        … process response …
        completion(response.1)    
    }
}

Alternatively, you could adopt Swift concurrency for this part of your project, allowing you to write linear code that acts asynchronously.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

[1] Most notably, an iPhone in Low Power Mode won’t run work on background queues.

You’ve combined a number of anti-patterns:

  • Don’t use Dispatch global concurrent queues. See Avoid Dispatch Global Concurrent Queues for an explanation as to why.

  • Using the .background QoS is tricky, because work on such queues can be delayed for a long time [1].

  • Don’t try to convert asynchronous code to synchronous code using a semaphore, or any other concurrency primitive for that matter.

Given the above, it’s hard to say exactly what’s going wrong. I recommend that you fix all of these issues and then post back if you continue to have problems.

Of these, only the last one is potentially challenging. However, I don’t think that’s a problem in your specific case. You have a getFeedURLData(…) routine that calls your requestSynchronousData(…) method and then processes the result. However, you don’t need to call URLSession synchronously here, because getFeedURLData(…) is already asynchronous, that is, it has a completion handler. So instead of this:

func getFeedURLData(…) {
    …
    let response = URLSession.requestSynchronousData(…)
    … process response …
    completion(response.1)    
}

do this:

func getFeedURLData(…) {
    …
    let response = make an asynchronous request {
        … process response …
        completion(response.1)    
    }
}

Alternatively, you could adopt Swift concurrency for this part of your project, allowing you to write linear code that acts asynchronously.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

[1] Most notably, an iPhone in Low Power Mode won’t run work on background queues.

Issue: API Call Delays (5-10 Minutes) on Real Device in tvOS 18 After Call Completes, Works Fine in Debug Mode and Simulator
 
 
Q