Правильный способ обнаружения отмененных пользователем загрузок с помощью AVAssetDownloadDelegate

#ios #swift #http-live-streaming #avassetdownloadtask

#iOS #swift #http-прямая трансляция #avassetdownloadtask

Вопрос:

надеясь, что у кого-то есть какие-то подсказки, мы попытались опубликовать их на форумах Apple, но они не помогли. Пытаюсь найти правильный способ обнаружения отмененной пользователем загрузки / извлечь код ошибки из объекта AVAssetDownloadTask с использованием AVAssetDownloadDelegate в Swift. Мы попытались использовать следующий метод:

 public func urlSession(_ session: URLSession, assetDownloadTask: AVAssetDownloadTask, didFinishDownloadingTo location: URL)
{
    if let errorCode = assetDownloadTask.error?._code,
        errorCode == NSURLErrorCancelled
    {
        do
        {
            try FileManager.default.removeItem(at: location)
        }
        catch
        {
            DDLogError("An error occurred trying to delete the contents on disk for (error)")
        }

        // if we do have a cancelled download and we have removed it, return before we save the location
        return
    }

    // we need to save the location where the download finished, so when we call our delegate in
    // urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?)
    // we have a reference to it in order to pass along
    self.locationDict[assetDownloadTask.urlAsset.url] = location
}
  

А также

 public func urlSession(_ session: URLSession, assetDownloadTask: AVAssetDownloadTask, didFinishDownloadingTo location: URL)  
{  
    if let error = assetDownloadTask.error as NSError?  
    {  
        switch (error.domain, error.code)  
        {  
            case (NSURLErrorDomain, NSURLErrorCancelled):  

                do  
                {  
                    try FileManager.default.removeItem(at: location)  
                }  
                catch  
                {  
                    DDLogError("An error occurred trying to delete the contents on disk for (error)")  
                }  

                // if we do have a cancelled download and we have removed it, return before we save the location  
                return  
            default:  
                DDLogError("An unexpected error occurred (error.domain)")  
        }  
    }  

    // we need to save the location where the download finished, so when we call our delegate in  
    // urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?)  
    // we have a reference to it in order to pass along  
    self.locationDict[assetDownloadTask.urlAsset.url] = location  
}  
  

Но оба отображаются в Crashlytics с журналом сбоев:

 Crashed: com.-.ios.application.AssetDownloadUrlSession  
0  libswiftFoundation.dylib       0x103afa01c specialized static URL._unconditionallyBridgeFromObjectiveC(_:)   8344  
1  Networking                     0x1027d2178 $S13Networking26AssetDownloadUrlSessionC03urlE0_05assetC4Task22didFinishDownloadingToySo12NSURLSessionC_So07AVAssetcH0C10Foundation3URLVtFTf4dnnn_n   456  
2  Networking                     0x1027ce3e8 $S13Networking26AssetDownloadUrlSessionC03urlE0_05assetC4Task22didFinishDownloadingToySo12NSURLSessionC_So07AVAssetcH0C10Foundation3URLVtFTo   88  
3  CFNetwork                      0x1dc049c78 __89-[NSURLSession delegate_AVAssetDownloadTask:didFinishDownloadingToURL:completionHandler:]_block_invoke   36  
4  Foundation                     0x1dc33c8bc __NSBLOCKOPERATION_IS_CALLING_OUT_TO_A_BLOCK__   16  
5  Foundation                     0x1dc244ab8 -[NSBlockOperation main]   72  
6  Foundation                     0x1dc243f8c -[__NSOperationInternal _start:]   740  
7  Foundation                     0x1dc33e790 __NSOQSchedule_f   272  
8  libdispatch.dylib              0x1db2e56c8 _dispatch_call_block_and_release   24  
9  libdispatch.dylib              0x1db2e6484 _dispatch_client_callout   16  
10 libdispatch.dylib              0x1db28982c _dispatch_continuation_pop$VARIANT$mp   412  
11 libdispatch.dylib              0x1db288ef4 _dispatch_async_redirect_invoke   600  
12 libdispatch.dylib              0x1db295a18 _dispatch_root_queue_drain   376  
13 libdispatch.dylib              0x1db2962c0 _dispatch_worker_thread2   128  
14 libsystem_pthread.dylib        0x1db4c917c _pthread_wqthread   472  
15 libsystem_pthread.dylib        0x1db4cbcec start_wqthread   4 
  

Комментарии:

1. есть решение для этого?

Ответ №1:

Вы можете реализовать эту опцию, это должно помочь вам избежать сбоя приложения

  func urlSession(_ session: URLSession, assetDownloadTask: AVAssetDownloadTask, didFinishDownloadingTo location: URL) {
        guard assetDownloadTask.urlAsset.assetCache?.isPlayableOffline == true,
            assetDownloadTask.error == nil else { return }
        locationDict[assetDownloadTask.urlAsset.url] = location
    }
  

Ответ №2:

Почему вы пытаетесь удалить файл, если он не загрузился?

self.locationDict[assetDownloadTask.urlAsset.url] = местоположение

Я думаю, что сбой здесь [assetDownloadTask.urlAsset.url] В этом случае это значение может быть равно нулю

Комментарии:

1. Мы не удаляем загрузку, если она не загрузилась, мы удаляем только в том случае, если пользователь явно отменяет / удаляет содержимое во время его загрузки, в чем и заключается вся проблема. Чтобы определить, что пользователь отменил его, нам нужно получить код ошибки, приведя ошибку к NSError и проверив, равно ли оно NSURLErrorCancelled

2. И если вы заметили журнал сбоев, он не выходит из строя из-за того, что в словарь вставлено значение nil, сбой: specialized static URL._unconditionallyBridgeFromObjectiveC(_:)

3. Эта ошибка означает, что вы получили какое-то необязательное значение или пытаетесь присвоить необязательное значение значению obj c.

4. Странно, свойство urlAsset AVAssetDownloadTask является AVURLAsset, а не необязательным. И свойство url набора urlAsset — это тип URL, который также не является необязательным. Я думаю, поскольку я не могу безопасно развернуть их как дополнительные, я проверю, что они не равны нулю другим способом. Спасибо

Ответ №3:

Сталкиваюсь с той же проблемой, так что, оказывается, url свойство AVURLAsset может быть nil , даже если оно не определено как необязательное. Вот уродливое, но безотказное решение для этого:

 

private extension AVURLAsset {
    var isURLNil: Bool {
        debugDescription.contains("URL = (null)")
    }
}
  

Очевидно, что это может привести к (маловероятным) будущим изменениям в том, как Swift печатает описания отладки, но до тех пор они, вероятно, также исправят эту ошибку во фреймворке.