twilio / conversations-ios

SPM releases

Home Page:https://www.twilio.com/docs/conversations/ios/changelog

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Crash when accessing media URL,

Vaidios opened this issue · comments

Hello,

I started experienced crashes when fetching media URL. Seems like either Twilio or my implementation fails to work when Twilio Cache stops existing (?). At first I thought it is because I used deprecated methods for temporary URL, but it still crashes when using new API.

My implementation for URL fetch goes like this:

extension TCHMessage {

  func extractChatAttachments() -> [ChatAttachment] {
    attachedMedia.map { constructChatAttachment(from: $0) }
  }
  
  private func constructChatAttachment(from media: Media) -> ChatAttachment {
    let downloadAction: ChatAttachment.DownloadAction = { [weak self] continuation in
      self?.getTemporaryContentUrlsFor(
        media: [media],
        completion: { result, urls in
          if let error = result.error {
            continuation(.failure(error))
          } else if result.isSuccessful,
                    let urls = urls {
            guard let url = urls[media.sid] else { continuation(.failure(TwilioError.fetchUrlForFileFailed)); return }
            continuation(.success(url.absoluteString))
          } else {
            continuation(.failure(TwilioError.fetchUrlForFileFailed))
          }
        }
      )
    }
    
    return ChatAttachment(filename: media.filename,
                          mediatype: media.contentType,
                          size: media.size,
                          downloadAction: downloadAction)
  }
}

where download action is
typealias DownloadAction = (@escaping (Result<String, Error>) -> Void) -> Void

Here is the stack trace:

Crashed: com.apple.root.user-initiated-qos.cooperative
0  TwilioConversationsClient      0x146d0 specialized ExpirableCache.recycle() + 300
1  TwilioConversationsClient      0x13f58 specialized ExpirableCache.subscript.getter + 404
2  TwilioConversationsClient      0x18b90 specialized MediaClient.getTemporaryContentUrlList(forMediaWithSids:completion:) + 100
3  TwilioConversationsClient      0x16018 @objc MediaClient.getTemporaryContentUrlList(forMediaWithSids:completion:) + 108
4  TwilioConversationsClient      0x54d48 -[TwilioConversationsClient getTemporaryContentUrlsForMediaSids:completion:] + 204
5  TwilioConversationsClient      0x54bfc -[TwilioConversationsClient getTemporaryContentUrlsForMedia:completion:] + 248
6  TwilioConversationsClient      0x416d4 -[TCHMessage getTemporaryContentUrlsForMedia:completion:] + 176
7  --REDACTED--                         0xfbb14 closure #1 in TCHMessage.constructChatAttachment(from:) + 11 (TCHMessage+FileData.swift:11)
8  --REDACTED--                         0x47744 FileMessageViewModel.fetchFileURL() + 4301715268 (<compiler-generated>:4301715268)
9  libswift_Concurrency.dylib     0x3b7cc swift::runJobInEstablishedExecutorContext(swift::Job*) + 244
10 libswift_Concurrency.dylib     0x3c1e8 swift_job_runImpl(swift::Job*, swift::ExecutorRef) + 72
11 libdispatch.dylib              0x15164 _dispatch_root_queue_drain + 396
12 libdispatch.dylib              0x1596c _dispatch_worker_thread2 + 164
13 libsystem_pthread.dylib        0x1080 _pthread_wqthread + 228
14 libsystem_pthread.dylib        0xe5c start_wqthread + 8

Have you experienced this issue before, I'd love to fix this crash, but it seems like there is nothing to fail at, especially that I keep a weak reference to TCHMessage.

I'd love to provide more info about this issue, hopefully we'll be able to resolve it :)

Hello,

I have never seen a crash like this and I am not sure how we can reproduce it.

What is the version of the framework you use?
Do you call this method from the main thread or from a background one?
I would like to see logs with the reproduction as well, can you share them via opening a ticket on a support page (add a reference to this ticket, so it will come fast to me)?

Hey,
Framework version: 2.2.6
This method is called from a background thread, it uses swift's async/await to transform completion handler based to async.

  func url() async throws -> URL {
    try await withCheckedThrowingContinuation { continuation in
      guard let downloadAction = downloadAction else {
        fatalError("\(#function) Cannot fetch url, closure hasn't been provided")
      }

      downloadAction({ result in
        switch result {
        case .success(let stringUrl):
          guard let url = URL(string: stringUrl) else {
            continuation.resume(throwing: ApplicationError.urlConversionFromStringFailed)
            return
          }
          continuation.resume(returning: url)
        case .failure(let error):
          continuation.resume(throwing: error)
        }
      })
    }
  }

Reproduction is quite difficult, as it requires an app to run for some time in the background with some urls already fetched. Then after some time (I guess when ExpirableCache expires), for example coming from a push notification, it will crash when loading the same url that was already loaded.

Thank you for this report, I've found the root cause and the fix will be available soon. I will update this ticket once we release the new version.

Oh, I'm really glad I could help and I can't wait for the update. Please let me know if you need anything else :)

The version with a fix has been released, feel free to open a new ticket any time!