swiftstreamingurlsessionnsurlsessionconfiguration

Delegate Methods for URLSession streamTask Not Called


I'm trying to establish a persistent connection with an IMAP server so that whenever the server sends something over the stream, my app will be notified and be able to respond accordingly.

Here is what I have set up so far:

class Mailer: NSObject, URLSessionDataDelegate{
  static let shared = Mailer()
  var stream: URLSessionStreamTask!
  var session: URLSession!

  override init(){
    super.init()

    session = URLSession(configuration: URLSessionConfiguration.default, delegate: self, delegateQueue: .main)
  
    //Initializing the connection should initiate a server greeting
    stream = session.streamTask(withHostName: "imap.gmail.com", port: 993)
    stream.startSecureConnection()
    stream.resume()

    //If I do a readData immediately here, I get a response, but none of the delegate methods fire
    Task{
      let (data, _) = try! await stream.readData(ofMinLength: 0, maxLength: 100000, timeout: 60)

      if let data = data, let response = String(data: data, encoding: .ascii){
        print(response) //This shows the IMAP server's greeting
      }
    }
  }
  
  func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive data: Data) {
    //I think this should fire with the initial server response
    print("urlSession didReceive")
    print("task data: %@", data as NSData)
  }

  func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) {
    //Nothing logs here
    print("urlSession didError")
      if let error = error as NSError? {
        print(error)
          print("task error: %@ / %d", error.domain, error.code)
      } else {
          print("task complete")
      }
  }
}

How can I set up a persistent delegate method that receives data from the IMAP stream?


Solution

  • You should conform to URLSessionStreamDelegate instead of URLSessionDataDelegate since you are creating a URLSessionStreamTask not a URLSessionDataTask.

    The urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive data: Data) method would only be called if you were using a URLSessionDataTask.

    The func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) is correctly called when closing the stream by calling closeRead() and closeWrite() on your URLSessionStreamTask.