我可以取消 JSONEncoder Swift 吗?

Posted

技术标签:

【中文标题】我可以取消 JSONEncoder Swift 吗?【英文标题】:Can I cancel a JSONEncoder Swift? 【发布时间】:2021-06-23 10:32:25 【问题描述】:

我有一个 JSONEncoder 编码一个 20mb 的文件,需要很长时间才能处理。如果它正在处理的数据发生变化,我想取消编码,并重新启动编码过程,但我想不出办法来做到这一点。有任何想法吗? 我可以再次调用 JSONEncoder.encode,但现在我将运行两个 30 秒的进程,并且内存和处理器开销增加一倍。 能取消上一个就太好了。

编辑:你们中的一些人要求查看我的编码器。这是我要说的导致最大瓶颈的原因...

func encode(to encoder: Encoder) throws 
        try autoreleasepool 
            var container = encoder.container(keyedBy: CodingKeys.self)
            try container.encode(brush, forKey: .brush)

            if encoder.coderType == CoderType.export 
                let bezierPath = try NSKeyedUnarchiver.unarchivedObject(ofClass: UIBezierPath.self, from: beziersData)
                let jsonData = try UIBezierPathSerialization.data(with: bezierPath, options: UIBezierPathWritingOptions.ignoreDrawingProperties)
                let bezier = try? JSONDecoder().decode(DBBezier.self, from: jsonData)
                try container.encodeIfPresent(bezier, forKey: .beziersData)
             else 
                try container.encodeIfPresent(beziersData, forKey: .beziersData)
            
        
    

【问题讨论】:

将您的编码器封装在一个可取消的对象中,例如 NSOperation 或使用 Combine 可能吗? 您使用的是哪个版本的 Swift? 如果您的模型数据允许您这样做,您应该考虑在块/子任务中执行此操作,例如 20MB 分为 100 个块,您在开始之前在 for 循环中一个接一个地执行此过程您可以检查每个子任务是否需要继续(此编码过程是否取消?)。如果它被取消,您可以从该点返回,而无需编码所有数据并清理您正在进行的文件等。只要您一次性执行此操作,它一旦启动就无法取消。跨度> @SalmanKhakwani 感谢您的回答。我正在使用 Swift 5 我也想知道,为什么 20mb 文件会导致性能问题。 JSONEncoder 不是你能得到的禁食,但仍然没有那么慢,20mb 应该是一个问题。您可能会考虑一种更快的替代方案,它可以在 1/10 的时间内从 20mb JSON 创建自定义表示,甚至更快。 【参考方案1】:

您可以使用OperationQueue 并将长时间运行的任务添加到该操作队列中。

var queue: OperationQueue?
//Initialisation
if queue == nil 
    queue = OperationQueue()
    queue?.maxConcurrentOperationCount = 1

queue?.addOperation 
    //Need to check the isCanceled property of the operation for stopping the ongoing execution in any case.
    self.encodeHugeJSON()

您也可以随时使用以下代码取消任务:

//Whenever you want to cancel the task, you can do it like this
queue?.cancelAllOperations()
queue = nil

什么是操作队列:

一个操作队列根据它们的队列调用其排队的操作对象 优先级和准备就绪。将操作添加到队列后,它 保留在队列中,直到操作完成其任务。你不能 添加后直接从队列中删除操作。

参考链接:

https://developer.apple.com/documentation/foundation/operationqueue https://www.hackingwithswift.com/example-code/system/how-to-use-multithreaded-operations-with-operationqueue

【讨论】:

OperationQueue.cancelAllOperations docs say Canceling the operations does not automatically remove them from the queue or stop those that are currently executing. 所以它取消了队列中所有的待处理任务,in-flight任务不能被取消. @TarunTyagi +1 感谢您提供此信息。我认为 OP 可以在操作队列中使用 isCanceled 标志,并在发现该标志已打开时放弃他们正在进行的任务。 我同意@TarunTyagi 的观点,如果内存是一个问题,那么在取消旧操作后开始新操作实际上会更糟糕,而不是等待当前编码完成。 @TarunTyagi 这就是我认为操作队列的行为方式。因此,一旦它“在飞行中”,似乎就无法取消它。把它分成更小的块似乎是目前唯一的选择,我希望避免。 @user139816 Breaking it into smaller chunks seems like the only option 是解决此问题的最明智的方法。这将允许您在飞行中取消编码过程(过程已启动(步骤 = 100),在第 15 步,用户已取消,您标记此过程已被取消,它仍将完成第 15 步,在开始第 16 步之前,它将检查取消并从那里退出)。

以上是关于我可以取消 JSONEncoder Swift 吗?的主要内容,如果未能解决你的问题,请参考以下文章

Swift/JSONEncoder:包含嵌套原始 JSON 对象文字的编码类

swift JSONEncoder() 如何编码 swift NSDate/ 数据类型?

Swift持久化存储对象到文件中JSONEncoder 与 JSONDecoder

Swift持久化存储对象到文件中JSONEncoder 与 JSONDecoder

Swift持久化存储对象到文件中JSONEncoder 与 JSONDecoder

Swift持久化存储对象到文件中JSONEncoder 与 JSONDecoder