查询CloudKit中的视频数组,下载并存储在Documents目录中-iOS的Swift 3教程

从CloudKit下载视频非常简单,但是我需要查看多个资源并弄清楚如何修复几个错误才能使所有这些工作正常进行。 本教程假定您具有CloudKit知识和使用documentDirectory的知识。 如果您不熟悉CloudKit,请查看此Ray Wenderlich教程。 这就是我用来学习基础知识的东西。

我们将在本教程中做什么

  • 有一系列我们要下载的视频名称。
  • 检查是否有任何下载
  • 创建一个查询,该查询将发送未下载的视频数组
  • 查询Cloudkit以查找我们需要的记录
  • 下载视频并将其存储在文档中

我假设您已经知道如何设置CloudKit并上传了视频。

步骤1:设定

这是我将在本教程中使用的视频名称的数组。 您将需要更改项目以匹配您在CloudKit中存储的名称。 在您的ViewController中:

 让arrayOfVideoNames = [“ Apple”,“ Banana”,“ Cantalope”] 

步骤2:获取文档目录的内容

创建一个新文件。 该文件将包含一个名为DocumentsDirectoryFunctions的结构,该结构将具有与documentsDirectory相关的所有功能。 此结构的主要目的是获取documentDirectory的内容,以便我们可以将其与arrayOfVideoNames进行比较。 fileManager和getDocumentsDirectoryPath被标记​​为私有,因为我们不需要在结构外部使用它们。 如果需要,只需删除“私有”即可。

  struct DocumentsDirectoryFunctions { 
私人让fileManager = FileManager.default
私有函数getDocumentsDirectoryPath()->字符串{
让directoryPaths = fileManager.urls(用于:.documentDirectory,在:.userDomainMask中)
让docsDirectory = directoryPaths [0] .path
返回docsDirectory
}

func getContentsOfDocumentsDirectory()-> [String] {
var tempArray:[字串] = []
做{
让filelist =试试fileManager.contentsOfDirectory(atPath:getDocumentsDirectoryPath())
用于文件列表{
打印(文件名)
tempArray.append(文件名)
}
}捕获让错误{
print(“错误:\(error.localizedDescription)”)
}
返回tempArray
}
  } 

步骤3:建立模型

 导入CloudKit 
 结构模型{ 

// 1
私人let docDirectoryFuncs = DocumentsDirectoryFunctions()

// 2
私人出租容器:CKContainer
私人让publicDB:CKDatabase
私人让privateDB:CKDatabase
  // 3 
在里面() {
容器= CKContainer.default()
publicDB = container.publicCloudDatabase
privateDB = container.privateCloudDatabase
}

// 4
列举ModelErrors:错误{
案例编号
案例编号
失败的案例ToPerformDBQuery
}
func fetchVideos(videoNames:[String]){// 5

}
}

这里发生了什么?

  1. 我们创建一个DocumentsDirectoryFunctions结构的实例。
  2. 我们创建对象的容器和数据库。 如果您使用的是自定义数据库,则可能会有所不同。
  3. 我们初始化对象
  4. 我们创建一个用于错误处理的枚举。
  5. 这将是我们从VC调用的功能。 它将包含许多私有Model函数。

查看我们是否已经下载了视频

接下来,我们将添加一个功能来检查是否已经从阵列下载了视频。

  //在我们的模型结构中 
 私人let docDirectoryFuncs = DocumentsDirectoryFunctions() 
 私有函数checkToSeeIfVideosAreAlreadyDownloaded(videoNames:[String])-> [String] { 
var videoNamesThatNeedToBeDownloaded:[String] = []

let filesInDocsDirectory = docDirectoryFuncs.getContentsOfDocumentsDirectory()// 1
videoNames中的videoName {
let videoNameWithExtension =“ \(videoName).mp4” // 2

如果filesInDocsDirectory.contains(videoNameWithExtension){
打印(“ \(videoName)已下载”
}其他{
打印(“需要下载\(videoNameWithExtension)”)

videoNamesThatNeedToBeDownloaded.append(videoName)// 3
}
}
返回videoNamesThatNeedToBeDownloaded
}

这里发生了什么?

  1. 这将获取我们文档目录中的所有文件。
  2. 我们添加扩展名是因为这将为我们的文件命名。 (“视频名称.mp4”)
  3. 注意:我们不会将videoNameWithExtension添加到此数组中,因为在查询CloudKit时,我们仅使用视频名称。

创建我们的查询

这将使用所有未下载的视频名称创建一个CloudKit查询。

  //在我们的模型类中 
 私有函数getQueryFromNamesArray(names:[String])-> CKQuery { 
让arrayPredicate = NSPredicate(格式:“名称输入%@”,argumentArray:[名称])
let query = CKQuery(recordType:“ Videos”,谓词:arrayPredicate)
返回查询
}

步骤4:创建对CloudKit记录的引用结构

创建一个新文件。 创建一个结构。 这是对CloudKit中的记录及其数据库的引用。 (这仅是参考,不包含视频。)

 导入CloudKit 
struct VideosInCloudKit {
var名称:字符串!
var record:CKRecord!
弱var数据库:CKDatabase!

init(名称:字符串,记录:CKRecord,数据库:CKDatabase){
self.name =名称
self.record =记录
self.database =数据库
}
}

步骤5:查询公共数据库

返回您的模型文件。

在本教程中,我们查询公共数据库,但是您可以根据需要修改此函数以查询其他数据库。

  //在我们的模型结构中 
 func queryPublicDatabase(query:CKQuery){ 

publicDB.perform(query,inZoneWith:nil){(结果,错误)在
如果让错误=错误{
print(“获取项目\(错误)时出错”)
返回
}
DispatchQueue.main.async {
结果?.forEach({(记录:CKRecord)在

let record = VideosInCloudKit(name:record.value(forKey:“ Name”)as!字符串,记录:记录,数据库:self.publicDB)
做{
尝试self.saveVideoToDocumentsDirectory(视频:记录)
}捕获ModelErrors.noName {
打印(“错误文件无名称”)
}捕获ModelErrors.noRecord {
打印(“错误,没有文件记录”)
} {
打印(错误)
}
})

}
}
}

该方法执行查询,如果成功,它将调用saveVideoToDocumentsDirectory,我们将很快创建它。

步骤6:将视频保存到文档目录

  //在我们的模型结构中 
 私人功能saveVideoToDocumentsDirectory(video:VideosInCloudKit)抛出{// 1 
// 2
警卫让记录= video.record其他{
抛出ModelErrors.noRecord
}
警卫让名称= video.name其他{
抛出ModelErrors.noName
}

// 3
DispatchQueue.global(qos:DispatchQoS.QoSClass.background).async {
让videoFile = record.object(forKey:“ Video”)为! 知识资产
让videoURL = videoFile.fileURL作为URL!
做{
让videoData =试试数据(contentsOf:videoURL!)
让documentsPath = NSSearchPathForDirectoriesInDomains(.documentDirectory,.userDomainMask,true)[0]
让destinationPath = NSURL(fileURLWithPath:documentsPath).appendingPathComponent(“ \(name).mp4”,isDirectory:false)
FileManager.default.createFile(atPath:destinationPath!.path,内容:videoData,属性:无)

} {
打印(“下载视频时出错”)
}
}
}

这里发生了什么?

  1. 如果参数对象没有记录或名称,我们将使用抛出。 (我们需要记录来下载文件和用于创建文件名的名称)
  2. 如果使用let语句,则嵌套这些保护语句是更好的选择
  3. 我们尝试将视频下载并保存在后台线程中,因此我们在下载时不会冻结该应用程序。

步骤7:放在一起

  //在我们的模型结构中 
  func fetchVideos(videoNames:[String]){ 
 让undownloadedVideos = checkToSeeIfVideosAreAlreadyDownloaded(videoNames:videoNames) 
 让查询= getQueryFromNamesArray(名称:undownloadedVideos) 
  queryPublicDatabase(查询:查询) 
  } 

这是您将从VC中调用的功能。 将视频标题数组作为参数。

结论

妳去 您现在可以从CloudKit下载视频文件,并将其保存在“文档目录”中。 从那里您可以播放它们。 如果您可以改进此代码,请发表评论。 我不是这方面的专家,我之所以这样做,是因为尝试在自己的应用中实现时找不到相似的东西。

如果这可以帮助您,请订阅,如果您想要更多这样的帖子。 每当我遇到一个需要多个来源解决的问题时,我都会发表其中一篇文章。 也请让我知道如何改善本教程的编写方式。 谢谢

aestusLabs的教程。 分享您的知识。