在 Core Data 中存储 URLSessionDownloadTask

Posted

技术标签:

【中文标题】在 Core Data 中存储 URLSessionDownloadTask【英文标题】:Store URLSessionDownloadTask in Core Data 【发布时间】:2017-06-02 10:35:31 【问题描述】:

当应用程序处于关闭状态或我的下载状态发生更改(例如从等待状态变为下载状态或完成状态)时,我想将 URLSessionDownloadTask 保存在核心数据中。

我的自定义类的所有其他属性都已完美存储,但应用程序在存储下载任务时会崩溃。

崩溃的原因是

[__NSCFLocalDownloadTask encodeWithCoder:]:无法识别的选择器发送到实例 0x7ff189f181c0 -[NSKeyedArchiver dealloc]:警告:NSKeyedArchiver 在没有调用 -finishEncoding 的情况下被释放。 由于未捕获的异常“NSInvalidArgumentException”而终止应用程序,原因:“-[__NSCFLocalDownloadTask encodeWithCoder:]:无法识别的选择器发送到实例 0x7ff189f181c0”

这是我的课

class VideoDownloadModel : NSManagedObject 

    @NSManaged var videoID : NSNumber?
    @NSManaged var vid : Video?
    @NSManaged var downloadTask : URLSessionDownloadTask?
    @NSManaged var downloadStatus : String?

这样保存

    let request = NSFetchRequest<NSFetchRequestResult>(entityName: (COREDATA_ENTITY_Description?.name)!)
    request.returnsObjectsAsFaults = false
    request.predicate = NSPredicate(format: "videoID == %@", videoModel.videoID!)

        do 
            let result = try COREDATA_CONTEXT.fetch(request)
            print(result)
            var vidArr = result as! [VideoDownloadModel]

            if vidArr.count != 0 
                vidArr[0] = videoModel

                COREDATA_MANAGER.saveContext()
            

         catch 
            let fetchError = error as NSError
            print(fetchError)
        

URLSessionDownlaodTasknil 时,它可以正常工作,但是当任何下载开始时,它会在保存时崩溃。

场景:

我用所有属性初始化了我的自定义类对象,但将任务设置为 nil。

我将该对象存储在它完美保存的核心数据中。

我初始化了该对象的任务,下载工作完美。

然后我更新核心数据中的对象,同时更新应用程序崩溃了,因为 URLSssionTask 不是从 NSCoding 继承的。所以它没有编码和解码方法。

我想要一些解决方案来解决这个问题

任何帮助将不胜感激。谢谢。

【问题讨论】:

请展示如何你是如何做到的(代码)。 我已将其添加到我的帖子中,请查看它。 我强烈怀疑您是否会在从 Core Data 获取任务后恢复它。 Vadian no 任务未恢复。让我分享 1 个完整的场景: 1- 我用所有属性初始化了我的自定义类对象,但将任务设置为 nil。 2-我将该对象存储在它完美保存的核心数据中。 3-我初始化该对象的任务,下载工作完美。 4-然后我更新核心数据中的对象,同时更新应用程序崩溃了,因为 URLSssionTask 不是从 NSCoding 继承的。所以它没有编码和解码方法。现在我想要一些解决方案来解决这个问题。 【参考方案1】:

您不能将URLSessionDownloadTask 保存在Core Data 中,因为——正如你所提到的——它不符合NSCoding。在许多情况下,答案是编写您自己的代码来转换为Data 或从Data 转换,但这在这种情况下不起作用。 URLSessionDownloadTask只能由URLSession创建,所以不能序列化和反序列化任务对象。

但这并不重要,因为保存和恢复它们没有意义。 URLSessionDownloadTask 表示应用程序运行时正在进行的操作。如果您的应用程序已关闭,则该活动结束。在应用程序关闭并重新启动后恢复 URLSessionDownloadTask 没有任何意义,因为它没有可以表示的活动。基本上,即使您可以存储任务对象并对其进行恢复,恢复后也将毫无用处。没有理由打扰。

如果您希望恢复未完成的下载,则必须从头开始。创建您的URLSession,然后使用它创建一个新的URLSessionDownloadTask。如果您有兴趣获取有关后台下载的信息,您可以使用带有getTasksWithCompletionHandler(_:) 的会话对象来确定它们是否已完成。

【讨论】:

感谢您的回答,但您能否指导我在应用重新启动后如何恢复 youtube 下载?【参考方案2】:

保存URLSessionDownloadTask 没有意义。您实际上希望在暂停时保存从downloadTask.cancel(byProducingResumeData: ) 获得的数据。

一旦您需要恢复下载,请使用downloadTaskWithResumeData(:) 使用保存的数据创建一个新的下载任务并恢复。

应用终止时 - 不包括应用被用户强行终止的情况。

关于 URLSession 的苹果文档清楚地解释了应用程序终止时要做什么。 来自文档 - ios 和 OS X 中,当用户重新启动您的应用程序时,您的应用程序应立即创建具有与您的应用程序上次运行时具有未完成任务的任何会话相同的标识符的后台配置对象,然后创建一个每个配置对象的会话。这些新会话同样会自动与正在进行的后台活动重新关联。

当用户强行终止应用时

在这种情况下,URLSession 委托urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) 将被触发,其中error 对象中的userInfo dict 将具有与键NSURLSessionDownloadTaskResumeData 对应的恢复数据,可用于恢复任务使用downloadTask.cancel(byProducingResumeData: )。另请注意,您必须将error 类型转换为NSError 才能检索userInfo 字典。

在使用NSURLSession 之前,最好通读文档here

【讨论】:

是的,您是对的,但是当downloadTask.cancel(byProducingResumeData: ) 无法完成时如何处理。例如当用户强行退出应用程序时? 抱歉来晚了。我已经更新了答案。看看这是否有帮助(如果您还没有找到解决方案:D)

以上是关于在 Core Data 中存储 URLSessionDownloadTask的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Core Data 中存储没有时间的日期

在 Core Data 中存储指针

如何在 Core Data 中存储 CLPlacemark 地址数据

如何在 Core Data 中存储星期几?

在 NSLibraryDirectory 或 NSApplicationSupportDirectory 中存储 Core Data Sqlite?

使用 Core Data 存储位置数据