MailCore / mailcore2

MailCore 2 provide a simple and asynchronous API to work with e-mail protocols IMAP, POP and SMTP. The API has been redesigned from ground up.
Other
2.59k stars 623 forks source link

Crash during async .start() on Swift #1929

Open ahlager opened 2 years ago

ahlager commented 2 years ago

Hello, using the latest await/async paradigm in Swift I'm running into an error.

When calling fetchMessagesOperation with .start() async inside an async function, I get an error of :0: Fatal error: Unexpectedly found nil while implicitly unwrapping an Optional value. No matter if I have guards, checks, it will always hard crash.

However, running the same code but with the non-async version of .start(), it does not crash.

I have tested with other "fetch" functions/operations and I do not see the same results. Only with async fetchMessagesOperation.

Below is the code I'm using

ASYNC: This is the code that crashes

let index_set = MCOIndexSet(range: MCORange(location: UInt64(last_seen_uid) + 1, length: 20))

let fetch = safe_session.fetchMessagesOperation(withFolder: folder, requestKind: [.flags], uids: index_set)

do {
    guard let results = try await fetch?.start() else {return}  // <------ always crashes here

        // never gets here
    print(results)

        } catch let error as NSError {

            // this is never reached
            print(error.localizedDescription)
            return
}

NON-ASYNC: This does not crash

let index_set = MCOIndexSet(range: MCORange(location: UInt64(last_seen_uid) + 1, length: 20))

let fetch = safe_session.fetchMessagesOperation(withFolder: folder, requestKind: [.flags], uids: index_set)

fetch?.start({ _, messsages, _ in
     // do something with messages
})

Additionally, using the connectionlogger, the output data for each is exactly the same:

Optional("13 UID FETCH 2:22 (UID FLAGS)\r\n")
Optional("13 OK Completed (0.000 sec)\r\n")
okferret commented 2 years ago

session.delegateQueue.async { fetch?.start ({ *** }) }

cliftonlabrum commented 2 years ago

@ahlager I'm running into this same issue. Did you ever find a fix?

@imotoboy Can you elaboriate on that? Is session supposed to be an MCOIMAPSession object?

ahlager commented 2 years ago

@cliftonlabrum unfortunately no, this didn't work and I was not able to find a fix.

Be-Maps commented 1 year ago

This is a problem with XCode and mailcore works well. You cannot execute step by step as these lines go onto a different thread onto a different processor (and debugger is not able to return values properly). SOLUTION:

NOTE (XCode not always translates properly to async) For fetch messages you might need to write async extension (the below code works, and returns empty list or list of values):

extension MCOIMAPFetchMessagesOperation { func fetchMessages() async throws -> [Any] { typealias PostContinuation = CheckedContinuation <[Any], Error> return try await withCheckedThrowingContinuation { (continuation:PostContinuation) in self.start { (error: Error?, headers: [Any]?, indexSet: MCOIndexSet?) -> Void in if let error = error { print("Error downloading message UIDs: (error)") let mHeaders:[Any] = [] continuation.resume(returning: mHeaders) } else { print("Successful IMAP messages headers download") var mHeaders:[Any] = [] if (headers != nil) {mHeaders = headers!} continuation.resume(returning: mHeaders) }}}}