【问题标题】:How do I asynchronously download and cache videos for use in my app?如何异步下载和缓存视频以在我的应用程序中使用?
【发布时间】:2019-09-13 02:23:09
【问题描述】:

我知道SDWebImage 在后台线程中加载图像,因此在进行下载时您不会阻塞 UI/主线程。此外,它还会对您下载的所有图像进行磁盘缓存,并且永远不会从同一个URL 重新下载图像。

所以我想知道视频是否有相似或相同的东西?

注意事项:我将视频添加为子图层。

let videoURL = URL(string: postArray[indexPath.item].media[0].videoURLString!)//need to do error handlin here
print(videoURL as Any, "<-- video url in dispkay")

let player = AVPlayer(url: videoURL! as URL)
let playerLayer = AVPlayerLayer(player: player)
playerLayer.frame = CGRect(x: -8, y: 0, width: 138, height: 217)//cell.frame


cell.imageOrVideoView.layer.addSublayer(playerLayer)
//Other code and play()

This was recommended 过去,但它似乎做了一些不同的事情,或者在租用时有太多我不需要的额外功能。

更新:

我在测试什么:

  DispatchQueue.global(qos: .default).async(execute: {

            var downloadedData: Data? = nil
            if let url = URL(string: videoURL) {
                do {
                    downloadedData = try Data(contentsOf: url)
                } catch {
                    print(error, "downloaded Data failed")
                }
            }

            if downloadedData != nil {

                // STORE IN FILESYSTEM
                var cachesDirectory = NSSearchPathForDirectoriesInDomains(.cachesDirectory, .userDomainMask, true)[0]
                var file = URL(fileURLWithPath: cachesDirectory).appendingPathComponent(videoURL).absoluteString
                do {
                    try downloadedData?.write(to: URL(string: file)!)
                } catch {
                    print(error, "error dowloading data and writing it")
                }

                // STORE IN MEMORY
                if let downloadedData = downloadedData {
                    memoryCache?.setObject(downloadedData as AnyObject, forKey: videoURL as AnyObject)
                }
            }

            // NOW YOU CAN CREATE AN AVASSET OR UIIMAGE FROM THE FILE OR DATA
        })

但是我不明白我是应该在最后一行之后做某事,还是应该在 }) 之后做某事,或者我是否需要在此处添加更新 UI。

【问题讨论】:

  • 请让您的问题独立存在。 imageUrlString 是什么?
  • 什么算法?您的问题没有解释您的代码应该做什么。显示输入和所需输出的清晰示例并解释逻辑。

标签: ios swift asynchronous firebase-realtime-database


【解决方案1】:

所以我能够通过以下方式解决问题:

斯威夫特 4:

import Foundation

public enum Result<T> {
    case success(T)
    case failure(NSError)
}

class CacheManager {

    static let shared = CacheManager()
    private let fileManager = FileManager.default
    private lazy var mainDirectoryUrl: URL = {

    let documentsUrl = self.fileManager.urls(for: .cachesDirectory, in: .userDomainMask).first!
        return documentsUrl
    }()

    func getFileWith(stringUrl: String, completionHandler: @escaping (Result<URL>) -> Void ) {

        let file = directoryFor(stringUrl: stringUrl)

        //return file path if already exists in cache directory
        guard !fileManager.fileExists(atPath: file.path)  else {
            completionHandler(Result.success(file))
            return
        }

        DispatchQueue.global().async {

            if let videoData = NSData(contentsOf: URL(string: stringUrl)!) {
                videoData.write(to: file, atomically: true)
                DispatchQueue.main.async {
                    completionHandler(Result.success(file))
                }
            } else {
                DispatchQueue.main.async {
                    let error = NSError(domain: "SomeErrorDomain", code: -2001 /* some error code */, userInfo: ["description": "Can't download video"])

                    completionHandler(Result.failure(error))
                }
            }
        }
    }

    private func directoryFor(stringUrl: String) -> URL {

        let fileURL = URL(string: stringUrl)!.lastPathComponent
        let file = self.mainDirectoryUrl.appendingPathComponent(fileURL)
        return file
    }
}

用法:

      CacheManager.shared.getFileWith(stringUrl: videoURL) { result in

        switch result {
        case .success(let url):
        // do some magic with path to saved video

            break;
        case .failure(let error):
            // handle errror

            print(error, " failure in the Cache of video")
            break;
        }
    }

【讨论】:

  • 其实我觉得 DispatchQueue 在后台线程上运行 DispatchQueue.global(qos: .background).async { } 比较好
猜你喜欢
  • 2013-01-31
  • 1970-01-01
  • 2014-01-03
  • 1970-01-01
  • 2014-07-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-11-08
相关资源
最近更新 更多